Flutter StreamBuilder<DocumentSnapshot> not passing value into child StreamBuilder - flutter

I am trying to get a specific icon to appear based on whether the user has taken the survey or not.
At the moment, I am using StreamBuilder<DocumentSnapshot> to listen for a given value in a document, which returns the survey name. I then want to use the survey name in the next StreamBuilder, which will look in a given collection (which is made up of the survey name followed by _entrants - so, for example, Survey_entrants) for a completed survey document, which will have the title of the user's unique id (named userid).
The problem I have now is that whilst surveyName does return the name of the survey put in Cloud Firestore, and updates it when I change the value (I can see this by the commented-out return new Text('$surveyName'); command).
However, it does not seem to be passing that value into the next StreamBuilder - regardless of what I put in as the survey name, I get the check icon showing, suggesting (snapshot1.hasData) - even when that document does not exist.
I know the surveyName variable is working, but if I do snapshot1.toString() I get the error Snapshot<DocumentSnapshot>(ConnectionState.active, Instance of 'DocumentSnapshot', null). This must count has having data, hence showing the survey being taken. How do I correct this?
My code:
Positioned(
right: 30,
top: 20,
child: StreamBuilder<DocumentSnapshot>(
stream: Firestore.instance
.collection('Controller')
.document('Current Survey')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
} else {
var sn = snapshot.data;
surveyName = sn["cs"];
// return new Text('$surveyName');
return StreamBuilder(
stream: Firestore.instance
.collection('$surveyName' + '_entrants')
.document(userid)
.snapshots(),
builder: (BuildContext context, snapshot1) {
if (!snapshot1.hasData) {
return Icon(
Foundation.burst_new,
size: 48,
color: Color(0xff303841),
);
} else if (snapshot1.hasData) {
return Icon(
Foundation.check,
size: 48,
color: Color(0xff303841),
);
} else {
return Icon(
MaterialIcons.error_outline,
size: 48,
color: Color(0xff303841),
);
}
});
}
})),

Related

Error when extracting data from firebase into flutter app

I want to ask for some help or advice.
I have a simple form which stores data in Firebase.
I created a new page where I want to display that information. I am using StreamBuilder to display the data for the logged user.
return Scaffold(
appBar: AppBar(
title: const Text("Your upcoming appointments"),
),
body: SafeArea(
child: Column(
children: [
StreamBuilder(
stream: FirebaseFirestore.instance.collection('client_bookings_doc').where('email', isEqualTo: currentUser.currentUser!.email).snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
shrinkWrap: true,
itemBuilder: (context, i) {
var data = snapshot.data!.docs[i];
print(data['email']);
return Text(data['email']);
},
);
} else {
return const Text("error");
}
},
),
],
),
),
);
I don't understand why I am getting that error:
W/GooglePlayServicesUtil( 3777): .................. requires the Google Play Store, but it is missing.
E/GooglePlayServicesUtil( 3777): GooglePlayServices not available due to error 9
W/Firestore( 3777): (24.4.2) [GrpcCallProvider]: Failed to update ssl context: com.google.android.gms.common.GooglePlayServicesNotAvailableException
I was following a few tutorials online and they both work fine.
Any help will be appreciated.
Update: I changed the device to google pixel 2 and now the error is
W/ProviderInstaller( 5334): Failed to report request stats: com.google.android.gms.common.security.ProviderInstallerImpl.reportRequestStats [class android.content.Context, long, long]
This query doesn't match the document structure in your screenshot:
FirebaseFirestore.instance
.collection('client_bookings_doc')
.where('email', isEqualTo: currentUser.currentUser!.email)
.snapshots()
There is no collection client_bookings_doc in your screenshot. Instead there is a root collection client_bookings with a document client_bookings_doc and then a subcollection again named client_bookings.
If you want to query across all client_bookings collection, you can use a collection group query:
FirebaseFirestore.instance
.collectionGroup('client_bookings') // 👈
.where('email', isEqualTo: currentUser.currentUser!.email)
.snapshots()

(Flutter - Firestore) The getter 'documents' was called on null

I have stored the download links of images on Firestore while the images are in firebase storage.
I am trying to retrieve the links and display them via stream builder but I'm encountering an error.
What can I do to fix this.
StreamBuilder:
StreamBuilder(
stream: db
.collection("Highway Secondary School Announcements")
.doc()
.snapshots(),
builder: (context, snapshot) {
if (snapshot!= null && snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
} else if (snapshot.hasError) {
return Center(
child: Text("Snapshot Was Not Retrieved"),
);
}
for (int i = 0; i < snapshot.data.documents; i++) {
listOfUrls.add(snapshot.data.documents[i]['url']);
listOfPics.add(Padding(
padding: const EdgeInsets.only(top: 50, bottom: 50),
child: Image.network(listOfUrls[i]),
));
}
return Container(
child: ListView(
children: listOfPics,
),
);
}),
Error:
The getter 'documents' was called on null.
Receiver: null
Tried calling: documents
If you have doc(), you need to specify which documentation(doc('name')) you want to be read, otherwise, you could remove ".doc()".
Reference:Cloud Firestore
before
db.collection("Highway Secondary School Announcements").doc().snapshots()
after
db.collection("Highway Secondary School Announcements").snapshots()
Second question:
I used "final items = snapshot.data?.docs" to get documents from that snapshot.
Here has a nice example Cloud Firestore flutter
final items = snapshot.data?.docs.reversed;
for ( var item in items!) {
final itemName = item.get('name');
final itemLogo = item.get('logo');
final itemDate = item.get('date');
// String itemDate2 = DateTime.fromMillisecondsSinceEpoch(itemDate).toString();
final itemBubble = _getListItemWidget(
iconName: itemLogo,
titleName: itemName,
subTitleName: DateTime.now(),
scoreKeeper1: scoreKeeper1,
scoreKeeper2: scoreKeeper2,
scoreKeeper3: scoreKeeper3
);
itemBubbles.add(itemBubble);
}

Firestore Flutter How Sort Data using int fields

Hello i have a firestore db with structure
Root
.....Oder
.........Xyz1
______T:1
.........Xyz1
______T:1
when i get the data i want it to sort automatically in desending oder using the int value stored in 'T'
T is unique for every document
child: StreamBuilder(
stream: Firestore.instance.collection("Oder").snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return new Text('Loading...');
}
return new ListView(
reverse: true,
children: snapshot.data.documents.map((document) {
return new ListTile(
title: new Text(document['T'].toString()),
);
}).toList(),
);
},
),
This is my code here
I also have the same value of T as String as each document name so sorting with that gave me 1,10,11,2,3...
So i need to get sorted with the int value stored in T
This is
You can get the data with this line:
CollectionReference collectionReference = Firestore.instance.collection("data-collection");
But , you can get the ordered data with:
Query collectionReference = Firestore.instance.collection("data-collection").orderBy('field');
orderBy should returns a Query, you can no longer store it as a CollectionReference.

Getting a valid value from StreamBuilder<DocumentSnapshot> and a child StreamBuilder

I am trying to get a specific icon to appear based on whether the user has taken the survey or not.
At the moment, I am using StreamBuilder to listen for a given value in a document, which returns the survey name. I then want to use the survey name in the next StreamBuilder, which will look in a given collection (which is made up of the survey name followed by _entrants - so, for example, Survey_entrants) for a completed survey document, which will have the title of the user's unique id (named userid).
The problem I have now is that whilst surveyName does return the name of the survey put in Cloud Firestore, and updates it when I change the value (I can see this by the commented-out return new Text('$surveyName'); command).
However, it does not seem to be passing that value into the next StreamBuilder - regardless of what I put in as the survey name, I get the check icon showing, suggesting (snapshot1.hasData) - even when that document does not exist.
I know the surveyName variable is working, but if I do snapshot1.toString() I get the error Snapshot(ConnectionState.active, Instance of 'DocumentSnapshot', null). This must count has having data, hence showing the survey being taken. How do I correct this?
My code:
Positioned(
right: 30,
top: 20,
child: StreamBuilder<DocumentSnapshot>(
stream: Firestore.instance
.collection('Controller')
.document('Current Survey')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
} else {
var sn = snapshot.data;
surveyName = sn["cs"];
// return new Text('$surveyName');
return StreamBuilder(
stream: Firestore.instance
.collection('$surveyName' + '_entrants')
.document(userid)
.snapshots(),
builder: (BuildContext context, snapshot1) {
if (!snapshot1.hasData) {
return Icon(
Foundation.burst_new,
size: 48,
color: Color(0xff303841),
);
} else if (snapshot1.hasData) {
return Icon(
Foundation.check,
size: 48,
color: Color(0xff303841),
);
} else {
return Icon(
MaterialIcons.error_outline,
size: 48,
color: Color(0xff303841),
);
}
});
}
})),
The issue I had was that Cloud Firestore returns a DocumentSnapshot even when there is nothing in the database to return. So, I changed (snapshot1.hasData) to (snapshot1.data.exists) and this works as expected - the icon changes based on the response.

How to use setState for just one widget

I have a Future which takes a value from my Cloud Firestore database and displays an icon in the body of my app. If the value in the database changes, the icon updates. I have been using setState to rebuild my widget tree and this works fine - the app reacts almost instantly to changes in my Cloud Firestore database. This is great! Code:
Future<void> takenSurvey2() async {
final sn = await Firestore.instance
.collection('Controller')
.document('Current Survey')
.get();
surveyName2 = sn['cs'];
final snapShot = await Firestore.instance
.collection('$surveyName2' + '_entrants')
.document(userid)
.get();
if (snapShot.exists) {
takenSurvey = true;
} else {
takenSurvey = false;
}
setState(() {});
}
and the place where the icon is shown is coded like this (within a stack):
Positioned(
right: 30,
top: 20,
child: FutureBuilder(
future: takenSurvey2(),
builder: (context, snapshot) {
if (takenSurvey == false) {
return Icon(
Foundation.burst_new,
size: 48,
color: Color(0xff303841),
);
} else if (takenSurvey == true) {
return Icon(
Foundation.check,
size: 48,
color: Color(0xff303841),
);
} else
return Container();
})),
However, I've added in my AdMob adverts using the 'admob_flutter' package, and because setState seems to be constantly running, the advert cannot load - I just see a flashing box. If I remove setState from the code above, the adverts load, but the icons in my app do not update when the value in Cloud Firestore changes.
How do I either exclude my admob_flutter widget from setState, or just use setState (or something else) to only update my FutureBuilder widget? I would like to do so in a way which limits the number of calls on Cloud Firestore, but this is not essential.
Thanks!