How to get data from other collection in streambuilder - firebase

I am facing a problem and I cannot solve it, I have a collection "Posts" that contain users' posts, each post contains a uid of the owner of the post, and I have another collection named "users", and each user has his name and photo, I want to get the user's name and image to display on his post.
Posts Collection
Users Collection
I have seen this article but I did not benefit perhaps because I am a beginner.
My Code:
StreamBuilder(
stream: Firestore.instance
.collection('Posts')
.orderBy('date', descending: true)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
const Text('Loading...');
} else {
return ListView.builder(
physics:
NeverScrollableScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: snapshot
.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot mypost =
snapshot
.data.documents[index];
return Stack(
children: <Widget>[
Container(
decoration:
BoxDecoration(
borderRadius:
BorderRadius
.circular(
15.0),
),
child: Padding(
padding:
EdgeInsets
.all(8.0),
child: Column(
children: <
Widget>[
InkWell(
child: Row(
children: <
Widget>[
Container(
width:
32.0,
height:
32.0,
decoration: BoxDecoration(shape: BoxShape.circle, image: DecorationImage(fit: BoxFit.fill, image: NetworkImage(
// user image url
'Owner of post img')))),
SizedBox(
width:
10.0,
),
Text(
'Owner of post Name',
style: TextStyle(
color: Colors.white,
fontSize: 12.0,
fontWeight: FontWeight.bold,
fontFamily: 'BalooDa2'),
),
],
),
),
Padding(
padding:
EdgeInsets.all(
5.0),
child: Text(
'${mypost['text']}',
style: TextStyle(
color: Colors
.white,
fontSize:
16.0,
fontFamily:
'Tajawal',
height:
1.3),
textAlign:
TextAlign
.justify,
textDirection:
TextDirection.rtl),
),
],
),
),
),
],
);
});
}
return Container(
height: 0.0,
width: 0.0,
);
},
),

You can user nested StreamBuilders to fetch user detail from the uid you are getting from posts collection.I have added a query which will match uid from posts data and look for the documents in users collection where uid is equal to uid from posts collection.
StreamBuilder(
stream: Firestore.instance
.collection('Posts')
.orderBy('date', descending: true)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
const Text('Loading...');
} else {
return ListView.builder(
physics:
NeverScrollableScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: snapshot
.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot mypost =
snapshot
.data.documents[index];
return Stack(
children: <Widget>[
Container(
decoration:
BoxDecoration(
borderRadius:
BorderRadius
.circular(
15.0),
),
child: Padding(
padding:
EdgeInsets
.all(8.0),
child: Column(
children: <
Widget>[
StreamBuilder(
stream: Firestore.instance
.collection('users')
.where('uid', isEqualTo: mypost['uid'])
.snapshots(),
builder: (context, snapshot){
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return SizedBox();
case ConnectionState.active:
default:
break;
}
if (snapshot.hasError) print(snapshot.error);
DocumentSnapshot user = snapshot.data.documents[0];
return InkWell(
child: Row(
children: <
Widget>[
Container(
width:
32.0,
height:
32.0,
decoration: BoxDecoration(shape: BoxShape.circle, image: DecorationImage(fit: BoxFit.fill, image: NetworkImage(
// user image url
'${user['uimg']}')))),
SizedBox(
width:
10.0,
),
Text(
'${user['name']}',
style: TextStyle(
color: Colors.white,
fontSize: 12.0,
fontWeight: FontWeight.bold,
fontFamily: 'BalooDa2'),
),
],
),
);
},
),
Padding(
padding:
EdgeInsets.all(
5.0),
child: Text(
'${mypost['text']}',
style: TextStyle(
color: Colors
.white,
fontSize:
16.0,
fontFamily:
'Tajawal',
height:
1.3),
textAlign:
TextAlign
.justify,
textDirection:
TextDirection.rtl),
),
],
),
),
),
],
);
});
}
return Container(
height: 0.0,
width: 0.0,
);
},
),

Related

Retrieve stream value then call another stream based on the previous value using Flutter with firestore

**This posts collection and following collection are child nodes of user collection.Using below code snippets I can retrieve users posts directly.
But I want to retrieve only followed users posts. If particular user followed another user. That followed users id saved under followings collection
**
Container(
height: 225.0,
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("users")
.doc(userProfileID)
.collection("posts")
.orderBy('Post Date', descending: true)
.snapshots(),
builder: (context, snapshot) {
return !snapshot.hasData
? ShimmerPlaceHolder().homePosts(true)
: snapshot.data.docs.length.toString() == "0"
? Container(
height: 100.0,
width: 200.0,
child: Column(
children: [
SizedBox(
height: 30.0,
),
Text(
"You have no posts yet",
style: TextStyle(
fontSize: AppTheme.AppLightTheme.fontLarge,
fontFamily: 'AirbnbCereal'),
),
Image.asset(
'assets/images/home_picture.png',
height: 100.0,
width: 100.0,
),
],
),
)
: Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
height: 200,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data.docs.length,
itemBuilder: (BuildContext context, int index) {
Post postModel = Post.fromDocument(
snapshot.data.docs[index],
snapshot.data.docs.length);
return Container(
width: MediaQuery.of(context).size.width * 0.35,
child: Card(
//TODO: Add all images radius
color: AppTheme.AppLightTheme.unSelectColor,
child: snapshot.data.docs.length == null
? ShimmerPlaceHolder().homePosts(true)

Error is not showing after scanning a item thats not on the firestore database

I did this personal project of mine where a barcode scanner would scan for data inside firestore database. I have this problem when I scanned a barcode thats not on the database it wont show the error message is just shows a empty scan item container which I made. Let me know if someone can figure why. I tried everything still couldnt fix it.
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("products")
.where("barcode", isEqualTo: '$barcodeScanRes')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Dialog(
child: Container(
height: 300,
child: Text('Product Not Found'),
),
);
} else {
return Dialog(
child: Container(
height: 350,
child: Column(children: [
Container(
height: 350,
width: 165,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot products =
snapshot.data!.docs[index];
return ScanCard(products: products);
},
)),
]),
),
);
#Scan Card
class ScanCard extends StatelessWidget {
const ScanCard({
Key? key,
required this.products,
}) : super(key: key);
final DocumentSnapshot products;
#override
Widget build(BuildContext context) {
final user = FirebaseAuth.instance.currentUser;
String _userId = user!.uid;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.all(10.0),
height: 180,
width: 160,
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(16)),
child: Image.network(products['img']),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0 / 4),
child: Text(
products['name'],
style: TextStyle(
color: Colors.blueGrey,
fontSize: 18,
),
),
),
Column(
children: [
Text(
"Size: " + products['size'],
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14, color: Colors.brown),
),
SizedBox(
width: 30,
),
],
),
Row(
children: [
Text(
"\tRs. " + products['price'],
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
SizedBox(
width: 40,
),
Icon(
Icons.add_shopping_cart,
color: Colors.black,
size: 25,
),
],
),
SizedBox(
width: 10,
),
SizedBox(
child: Padding(
padding: const EdgeInsets.all(10),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
color: Colors.red,
child: Text(
"Add to cart",
style: TextStyle(color: Colors.white),
),
onPressed: () {
DocumentReference documentReference = FirebaseFirestore.instance
.collection('userData')
.doc(_userId)
.collection('cartData')
.doc();
documentReference.set({
'uid': FirebaseAuth.instance.currentUser!.uid,
'barcode': products['barcode'],
'img': products['img'],
'name': products['name'],
'size': products['size'],
'price': products['price'],
'id': documentReference.id
}).then((result) {
addToCartMessage(context).then((value) => {
Navigator.pop(context)
});
}).catchError((e) {
print(e);
});
},
),
),
)
],
);
}
}
The thing is you are showing Product not found based on the condition:- !snapshot.hasData but this conditon means that data is being fetched so at this time rather show a progress indicator.
And to handle when data is not present in backend then add another condition:- if(snapshot.data.docs.isEmpty) and here show your dialogbox of Product not found...
Final Code Snippet will look like:-
if (!snapshot.hasData)
return Center(child:CircularProgressIndicator));//or return a black container if you don't want to show anything while fetching data from firestore
else if (snapshot.data.docs.isEmpty) {
return Dialog(
child: Container(
height: 300,
child: Text('Product Not Found'),
),
);
} else {
return Dialog(
child: Container(
height: 350,
child: Column(children: [
Container(
height: 350,
width: 165,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot products =
snapshot.data!.docs[index];
return ScanCard(products: products);
},
)),
]),
),
);
}

snapshot.data.docs.length not working on flutter

I make some listview and it have likes and comments section. I want to show how many likes and comments that post had. The like section works by displaying the number of users who like it, i try to show it with snapshot.data.docs.length.toString() from firestore but when i try to show how many comments with same code as like section it not working and only get 0.
this is inside comments field
Padding(
padding: const EdgeInsets.only(top: 8),
child: Padding(
padding: const EdgeInsets.only(left: 15),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Container(
width: 80.0,
child: Row(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
GestureDetector(
onLongPress: () {
Provider.of<PostFunction>(context,
listen: false)
.showLikes(
context,
documentSnapshot
.data()['title']);
},
onTap: () {
print('Adding like...');
Provider.of<PostFunction>(context,
listen: false)
.addLike(
context,
documentSnapshot
.data()['title'],
Provider.of<AuthenticationService>(
context,
listen: false)
.getUserUid);
},
child: Icon(
FontAwesomeIcons.arrowAltCircleUp,
color: kGreyColor,
size: 18.0,
),
),
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('posts')
.doc(documentSnapshot
.data()['title'])
.collection('likes')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child:
CircularProgressIndicator());
} else {
return Padding(
padding:
const EdgeInsets.only(
left: 8.0),
child: RichText(
text: TextSpan(
text: snapshot
.data.docs.length
.toString(),
style: GoogleFonts
.openSans(
color:
kGreyColor,
fontSize: 16.0),
children: <TextSpan>[
TextSpan(
text: ' votes',
style: GoogleFonts
.openSans(
color:
kGreyColor,
fontSize: 16.0,
)),
]),
),
);
}
})
],
),
),
SizedBox(width: 20),
Container(
width: 150.0,
child: Row(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
GestureDetector(
onTap: () {
Provider.of<PostFunction>(context,
listen: false)
.showComments(
context,
documentSnapshot,
documentSnapshot
.data()['title']);
},
child: Icon(
FontAwesomeIcons.solidComments,
color: kGreyColor,
size: 16.0,
),
),
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection(' posts')
.doc(documentSnapshot
.data()['title'])
.collection('comments')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child:
CircularProgressIndicator());
} else {
return Padding(
padding:
const EdgeInsets.only(
left: 8.0),
child: Text(
snapshot.data.docs.length
.toString(),
style: GoogleFonts.openSans(
color: kGreyColor,
fontSize: 16.0),
),
);
}
}),
],
),
),
Spacer(),
Provider.of<AuthenticationService>(context,
listen: false)
.getUserUid ==
documentSnapshot.data()['useruid']
? IconButton(
icon: Icon(EvaIcons.moreVertical,
color: kGreyColor, size: 16),
onPressed: () {
Provider.of<PostFunction>(context,
listen: false)
.showPostOptions(
context,
documentSnapshot
.data()['title']);
})
: Container(width: 0.0, height: 0.0)
],
),
),
),
Replace
.collection(' posts')
with
.collection('posts')
in the “comments” section of the Streambuilder.
Your stream data is coming as empty as the database cannot find a collection with name (“ posts”).
So when you try to show how many comments the post had with the same code as the “likes” section it is not working and only getting 0 each time.
just declare the dataType of builder's arguments..i mean, builder:(BuildContext context,AsyncSnapshot snapShot).check the image
Could you please try this one?
StreamBuilder(
stream: firestoreDB,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
return ListView.builder(
itemCount: snapshot.data!.size,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(snapshot.data!.docs[index]['name']),
subtitle: Text(snapshot.data!.docs[index]['description']),
),
);
},
);
},
),

How would you properly redraw a widget that displays data from a SQLite database when the data in the database changes?

I store a selected quarter in a Sqlite database. This quarter is displayed in an appbar along with some text a user can click to take them to a page where they can change the selected quarter. Once the user selects a quarter from the page, I push this neq quarter to the sqlite database so it can be displayed. I also use a Navigator.pop(context); to go back to the previous page when a new quarter is selected. My problem is that once a user selects a new quarter, the quarter isn't displayed on the page they were just on. You have to navigate away to see it or navigate away and back. the FutureBuilder doesn't seem to know that there is new data in the SQLite database that needs to be displayed. How would I go about making it display the new data when a user selects a new quarter? Any help is appreciated! Thanks!
How I display quarters. Also where the button to take you to the page to change quarters is.
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: FutureBuilder<dynamic>(
future: SessionDBProvider.sessionDB.getSessionObject(),
initialData: List(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
print(
'${snapshot.error}',
);
}
}
List session = snapshot.data;
return Container(
child: Column(children: <Widget>[
Flexible(
flex: 2,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue, Colors.red],
begin: Alignment.topRight,
end: Alignment.topLeft,
stops: [0.2, 1])),
child: Container(
margin: EdgeInsets.only(left: 11),
child: Text(
"Test Page",
style: TextStyle(
color: Colors.white,
fontSize: 27,
fontFamily: 'Montserrat',
height: 1.1),
),
),
)
],
),
),
Flexible(
flex: 2,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
margin: EdgeInsets.only(left: 10),
child: Text(
"${session[0].selected_quarter}",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 25),
),
),
],
),
),);
}));
}
This is where you select a new quarter and push it to the Sqlite database.
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[200],
appBar: PreferredSize(
preferredSize: Size.fromHeight(95.0),
child: AppBar(
automaticallyImplyLeading: false, // hides leading widget
flexibleSpace: DataAppBar(),
),
),
body: FutureBuilder<dynamic>(
future: DataDBProvider.dataDB.getData(),
initialData: List(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
print(
'${snapshot.error}',
);
}
}
List data = snapshot.data;
return ListView.builder(
itemCount: snapshot.data.length,
shrinkWrap: true,
itemBuilder: (context, int index) {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 1.0, horizontal: 4.0),
child: Card(
color: (index % 2 == 0) ? greycolor : Colors.white,
child: Container(
height: 60,
padding: EdgeInsets.fromLTRB(0, 20, 0, 0),
child: InkWell(
onTap: () {
Data data = new Data();
data.quarter_status = data[index].status;
data.selected_quarter = data[index].quarter;
DataDBProvider.sessionDB.updateSession(session);
Navigator.pop(context);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.only(right: 5),
child: Text(data[index].quarter,
style: TextStyle(
fontSize: 20,
fontFamily: 'Montserrat',
color: Colors.blue),
textAlign: TextAlign.left),
),
],
),
),
),
),
);
},
);
}));
}}

Firebase Streambuilder

I have a map in Firebase Database like this,
'abc#gmail.com' : { food order }
I want to create a stream of this data to update widgets when a new order is placed.
I tried using the below code but it is giving error.
DocumentSnapshot has no instance getter 'length'
StreamBuilder(
stream: Firestore.instance.collection('admin').document('current-orders').snapshots(),
builder: (context, snapshot) {
return snapshot.hasData?Column(
children: <Widget>[
Expanded(
child: Container(
child: Padding(
padding: EdgeInsets.all(10),
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, uid) {
return Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
snapshot.data.keys.toList()[uid],
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold),
),
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30)),
color: Colors.blue[200],
child: Text(
'Order Ready',
style: TextStyle(color: Colors.black54),
),
onPressed: () {},
),
],
),
ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemCount: snapshot.data.values.keys.toList().length,
itemBuilder: (context, orderID) {
return Text(
'${snapshot.data.values.keys[orderID].toString()} : ${snapshot.data.values.values[orderID].toString()}',
//'${_currentOrders[uid].keys.toList()[orderID]} : ${_currentOrders[uid].values.toList()[orderID]}',
style: TextStyle(fontSize: 16),
);
},
),
Padding(
padding: EdgeInsets.only(top: 10),
child: Container(
color: Colors.grey,
height: 1,
),
)
],
);
},
),
),
),
),
],
):Center(child: Text('No orders right now', style: TextStyle(fontSize: 30, color: Colors.black54),),);
}
);
Thank you.

Resources