How to retrive firebase subDocs - flutter - firebase

I want to retrieve a sub doc from Firebase, I need to collect the number of questions asked and answered by a particular user on their profile page, I am successfully retrieving the no of questions, cuz it's in the main doc,image 1, main doc, but I am not able to retrieve the answers, its a sub doc of questions image 2 sub doc, I tried playing with changing from AsyncSnaphot - DocumentSnapshot - dynamic, but no luck anywhere. Thanking you in advance.
```Widget followers(
BuildContext context, AsyncSnapshot<DocumentSnapshot> asyncSnapshot) {
return Container(
color: constantColors.green,
height: MediaQuery.of(context).size.height*0.09,
child: Row(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('questions')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Container();
} else {
return Provider.of<Authentication>(context, listen: false)
.getUserUid ==
asyncSnapshot.data.data()['user uid']
? Text(snapshot.data.docs.length.toString(), style: TextStyle(fontSize: 24),)
: Text('0');
}
}),
Text('asked'),
],
),
Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('questions').doc().collection('answers')
.snapshots(),
builder: (context, snapshot){
if (snapshot.connectionState == ConnectionState.waiting) {
return Container();
} else {
return Provider.of<Authentication>(context, listen: false)
.getUserUid ==
asyncSnapshot.data.data()['user uid']
? Text(snapshot.data.docs.length.toString(), style: TextStyle(fontSize: 24),)
: Text('0');
}
}),
Text('answered')
],
)
],
),
);
} ```
Edit: Adding more code of my answer adding to the firebase feature
answerAdder(BuildContext context,
AsyncSnapshot<DocumentSnapshot> documentSnapshot, String QuesID) {
return showModalBottomSheet(
elevation: 0,
backgroundColor: Colors.transparent,
isScrollControlled: true,
context: context,
builder: (context) {
return Container(
height: MediaQuery.of(context).size.height * 0.8,
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(horizontal: 5),
decoration: BoxDecoration(
color: constantColors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(25), topLeft: Radius.circular(25)),
),
child: Column(
children: [
Divider(
indent: 110,
endIndent: 110,
thickness: 4,
color: Colors.grey,
),
Padding(
padding: const EdgeInsets.all(5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
MaterialButton(
onPressed: () {
Provider.of<PostFunctions>(context, listen: false)
.addAnswer(
context,
documentSnapshot.data.data()['question id'],
answerController.text,
titleController.text)
.whenComplete(() {
Navigator.pop(context);
});
Navigator.pop(context);
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
color: constantColors.cyangrad,
child: Text(
'add answer',
style: TextStyle(fontWeight: FontWeight.w600),
),
)
],
),
),
Container(
height: MediaQuery.of(context).size.height * 0.2,
child: Padding(
padding: const EdgeInsets.all(5.0),
child: TextField(
controller: answerController,
maxLines: 8,
cursorColor: constantColors.green,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15),
hintText: 'Please enter your answer',
isDense: true,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide.none),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide.none),
fillColor: Colors.grey[300],
filled: true),
),
),
),
Container(
height: MediaQuery.of(context).size.height * 0.2,
child: Padding(
padding: const EdgeInsets.all(5.0),
child: TextField(
controller: titleController,
maxLines: 8,
cursorColor: constantColors.green,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15),
hintText: 'Please enter your title',
isDense: true,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide.none),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide.none),
fillColor: Colors.grey[300],
filled: true),
),
),
),
],
),
);
});}
Future method of uploading answer
Future addAnswer(BuildContext context, String postId,
String answer, String answerTitle) async {
return FirebaseFirestore.instance
.collection('questions')
.doc(postId)
.collection('answers')
.doc(answerTitle)
.set({
'answer': answer,
'username': Provider.of<FirebaseOps>(context, listen: false).initUsername,
'user uid':
Provider.of<Authentication>(context, listen: false).getUserUid,
'userimage':
Provider.of<FirebaseOps>(context, listen: false).initUserimage,
'useremail':
Provider.of<FirebaseOps>(context, listen: false).initUseremail,
'time': Timestamp.now(),
});
}

The issue is in .collection('questions').doc().collection('answers')
You need to pass the doc name in the doc() function. Consider it as a path!
By your example, it should be: .collection('questions').doc('hoo lala').collection('answers')

Related

Flutter update UI on button press

If I remove the awaits from my viewModel.sendMessage() it works as expected, however I can't set the state with the value returned. Is there a way to update the UI from setState?
I'm just not sure how to do both at the same time, the parent class for this widget is a StatefulWidget, Idk if that matters. My ConversationViewModel is just a changeNotifier.
#override
Widget build(BuildContext context) {
UsViewModel viewModel = Provider.of<UsViewModel>(context, listen: false);
viewModel.setUs();
var us = Provider.of<UsViewModel>(context, listen: true).us;
return Consumer<ConversationViewModel>(builder: (BuildContext context, viewModel, Widget child) {
return Scaffold(
key: viewModel.scaffoldKey,
appBar: AppBar(
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.keyboard_backspace,
),
),
elevation: 0.0,
titleSpacing: 0,
title: buildName(),
),
body: Container(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
Flexible(
child: StreamBuilder(
stream: messageListStream(widget.chatId),
builder: (context, snapshot) {
if (snapshot.hasData) {
List messages = snapshot.data.docs;
return ListView.builder(
controller: scrollController,
padding: EdgeInsets.symmetric(horizontal: 10.0),
itemCount: messages.length,
reverse: true,
itemBuilder: (BuildContext context, int index) {
Message message = Message.fromJson(
messages.reversed.toList()[index].data());
return ChatBubble(
message: '${message.content}',
time: message?.time,
isMe: message?.senderUid == us?.uid,
type: message?.type);
},
);
} else {
return Center(child: circularProgress(context));
}
},
),
),
Align(
alignment: Alignment.bottomCenter,
child: BottomAppBar(
elevation: 10.0,
child: Container(
constraints: BoxConstraints(maxHeight: 100.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
child: TextField(
controller: messageController,
focusNode: focusNode,
style: TextStyle(
fontSize: 15.0,
color:
Theme.of(context).textTheme.headline6.color,
),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
enabledBorder: InputBorder.none,
border: InputBorder.none,
hintText: "Type your message",
hintStyle: TextStyle(
color:
Theme.of(context).textTheme.headline6.color,
),
),
maxLines: null,
),
),
IconButton(
icon: Icon(
Feather.send,
color: Theme.of(context).colorScheme.secondary,
),
onPressed: () {
if (messageController.text.trim().isNotEmpty) {
sendMessage(viewModel, us);
}
},
),
],
),
),
),
)
],
),
),
);
});
}
sendMessage(ConversationViewModel viewModel, var us,
{bool isImage = false, int imageType}) async {
String msg;
msg = messageController.text.trim();
messageController.clear();
Message message = Message(
content: '$msg',
senderUid: us?.uid,
time: Timestamp.now(),
);
if (msg.isNotEmpty) {
String id = await viewModel.sendMessage(widget.usId, message);
setState(() {
chatId = id;
});
}
}
If you using ChangeNotifier with Provider package you don't need setState method. You should read Provider documentation: https://pub.dev/packages/provider
ft: That you create listeners for each item in this line.
isMe: message?.senderUid == context.watch<UsViewModel>.us ?.uid,
How to use a provider according to your question, added an example;
#override
Widget build(BuildContext context) {
context.read<UsViewModel>().setUs();
return Scaffold(
key: context.read<UsViewModel>().scaffoldKey,
appBar: AppBar(
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.keyboard_backspace,
),
),
elevation: 0.0,
titleSpacing: 0,
title: buildName(),
),
body: Container(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
Flexible(
child: StreamBuilder(
stream: messageListStream(widget.chatId),
builder: (context, snapshot) {
if (snapshot.hasData) {
List messages = snapshot.data.docs;
return ListView.builder(
controller: scrollController,
padding: EdgeInsets.symmetric(horizontal: 10.0),
itemCount: messages.length,
reverse: true,
itemBuilder: (BuildContext context, int index) {
Message message = Message.fromJson(
messages.reversed.toList()[index].data());
return ChatBubble(
message: '${message.content}',
time: message?.time,
isMe: message?.senderUid == context.watch<UsViewModel>.us ?.uid,
type: message?.type);
},
);
} else {
return Center(child: circularProgress(context));
}
},
),
),
Align(
alignment: Alignment.bottomCenter,
child: BottomAppBar(
elevation: 10.0,
child: Container(
constraints: BoxConstraints(maxHeight: 100.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
child: TextField(
controller: messageController,
focusNode: focusNode,
style: TextStyle(
fontSize: 15.0,
color:
Theme.of(context).textTheme.headline6.color,
),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
enabledBorder: InputBorder.none,
border: InputBorder.none,
hintText: "Type your message",
hintStyle: TextStyle(
color:
Theme.of(context).textTheme.headline6.color,
),
),
maxLines: null,
),
),
IconButton(
icon: Icon(
Feather.send,
color: Theme.of(context).colorScheme.secondary,
),
onPressed: () {
if (messageController.text.trim().isNotEmpty) {
sendMessage(context);
}
},
),
],
),
),
),
)
],
),
),
);
}
sendMessage(BuildContext context) async {
String msg;
msg = messageController.text.trim();
messageController.clear();
Message message = Message(
content: '$msg',
senderUid: context.read<UsViewModel>().us?.uid,
time: Timestamp.now(),
);
if (msg.isNotEmpty) {
String id = await context.read<UsViewModel>().sendMessage(widget.usId, message);
setState((){
chatId = id;
});
}
}

How to add "this user/account does not exist" error in Flutter, using Firebase?

I am trying to make a login page in Flutter. I have used Firebase as well for user authentication and logging in. The problem is, while I can login successfully with the correct information, I am unable to display anything like a pop up error box or message that the account does not exist. This is my code :
class _LoginPageState extends State<LoginPage> {
String _email, _password;
final auth = FirebaseAuth.instance;
bool hidepwd = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
brightness: Brightness.light,
backgroundColor: Colors.transparent,
elevation: 0,
leading: Container(
margin: EdgeInsets.all(5),
width: 50,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: Color(0xffe9eefa),
),
child: IconButton(
onPressed: (){Navigator.pop(context);},
icon: Icon(
Icons.keyboard_arrow_left_rounded,
color: Color(0xff2657ce),
),
),
),
),
body: ListView(
children: <Widget>[
Container(
child: IconButton(
icon: Icon(
Icons.account_circle_rounded,
color: Color(0xff2657ce),
size:100,
),
),
),
SizedBox(height: 50,),
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
padding: EdgeInsets.only(right: 240),
child: Text('Email Address', style: TextStyle(
fontSize: 15,),),
),
SizedBox(height: 10,),
Container(
padding: EdgeInsets.symmetric(vertical: 2, horizontal: 20),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Colors.grey.withOpacity(0.2),
),
child: TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'Email',
),
onChanged: (value) {
setState(() {
_email = value.trim();
});
},
),
),
SizedBox(height: 20,),
Container(
padding: EdgeInsets.only(right: 270),
child: Text('Password', style: TextStyle(
fontSize: 15,
),),
),
SizedBox(height: 10,),
Container(
padding: EdgeInsets.symmetric(vertical: 2, horizontal: 20),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Colors.grey.withOpacity(0.2),
),
child: Row(
children: <Widget>[
Expanded(
child: TextFormField(
obscureText: hidepwd,
decoration: InputDecoration(hintText: 'Password'),
onChanged: (value) {
setState(() {
_password = value.trim();
});
},
),
),
Container(
height: 50,
width: 50,
child: IconButton(
onPressed: togglepwdVisibility,
icon: IconButton(
icon: hidepwd == true ? Icon(
Icons.visibility_off
): Icon(Icons.visibility),
),
),
)
],
),
),
SizedBox(height: 20,),
RaisedButton(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
color: Color(0xff5178D7),
child: Text("Log In", style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 15
),),
onPressed: (){
auth.signInWithEmailAndPassword(email: _email, password: _password).then((_){
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context) => frontpage()));
});
}
),
SizedBox(height: 20,),
Container(
child: Center(
child: Text('---- or ----'),
),
),
SizedBox(height: 20,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Don't have an account? "),
InkWell(
onTap: openSignUpPage,
child: Text("Sign Up", style: TextStyle(
color: Color(0xff1A3C90),
fontWeight: FontWeight.w700
),),
)
],
)
],
),
),
),
],
),
);
}
Any ideas/suggestions on what I could add or change in my code to have that error message included when I am unable to login overall?
In your login onPressed: (){ ... }, catch the FirebaseAuthException.
Source: https://firebase.flutter.dev/docs/auth/usage/#sign-in
try {
UserCredential userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(
email: "barry.allen#example.com",
password: "SuperSecretPassword!"
);
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
print('No user found for that email.');
} else if (e.code == 'wrong-password') {
print('Wrong password provided for that user.');
}
}
If you need alerts to pop on each login error you can try using the following function but only if you are using TextEdittingController:
signIn() async {
if (_loginFormKey.currentState!.validate()) {
_loginFormKey.currentState!.save();
try {
await FirebaseAuth.instance
.signInWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text)
.then((currentUser) => FirebaseFirestore.instance
.collection("users")
.doc(currentUser.user!.uid)
.get()
.then((conext) => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomePage())))
.catchError((err) => print(err)));
} on FirebaseAuthException catch (error) {
if (error.code == 'user-not-found') {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Auth Exception!"),
content: Text("This User Does Not Exist."),
actions: <Widget>[
Row(
children: [
ElevatedButton(
child: Text("Sign In Again"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
)
],
);
});
} else if (error.code == 'wrong-password') {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Auth Exception!"),
content: Text("The Password Entered is Invalid."),
actions: <Widget>[
Row(
children: [
ElevatedButton(
child: Text("Sign In Again"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
)
],
);
});
}
}
}
}

Closure call with mismatched arguments: function '[]' in flutter

** I am getting this error**
Closure call with mismatched arguments: function '[]'
Receiver: Closure: (dynamic) => dynamic from Function 'get':.
Tried calling: []("url")
Found: [](dynamic) => dynamic
my code where I am receiving the data from firestore is this..
import 'package:flutter/material.dart';
import 'package:riyazat_quiz/services/database.dart';
import 'package:riyazat_quiz/views/create_quiz.dart';
import 'package:riyazat_quiz/widgets/widgets.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
Stream quizStream;
DatabaseService databaseService = DatabaseService(); // this is to call the getQuizData() async{
return await FirebaseFirestore.instance.collection("Quiz").snapshots();
}
Widget quizList(){
return Container(
child: StreamBuilder(
stream:quizStream ,
builder: (context,snapshort){
return snapshort.data == null ? CircularProgressIndicator(): ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount : snapshort.data.documents.length ,
itemBuilder : (context,index){ return QuizTile(url:snapshort.data.documents[index].get['url'],
title:snapshort.data.documents[index].get['title'] ,
desc: snapshort.data.documents[index].get['desc'],);}
);
}
),
);
}
#override
void initState() {
databaseService.getQuizData().then((val){
setState(() {
quizStream =val;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Center(
child: appBar(context),
),
backgroundColor: Colors.transparent,
elevation: 0.0,
brightness: Brightness.light,
),
body:
Column(
children: [
quizList(),
FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => CreateQuiz()));
},
),
],
),
);
}
}
class QuizTile extends StatelessWidget {
final String url,title,desc;
QuizTile({#required this.url,#required this.title,#required this.desc});
#override
Widget build(BuildContext context) {
return Container(
child: Stack(
children: [
Image.network(url),
Container(
child: Column(
children: [
Text(title),
Text(desc),
],
),
)
],
),
);
}
}
can someone tell me where I am going wrong
ps: this is a quiz app where I am getting the data from the firestore,
using streams.
data saved on the firestore has three fields, "url", "title" "desc".
I want to retrieve them in the below widget and want to display them in a stack, but this error got me stuck in-between.
You need to do the following:
itemCount : snapshort.data.docs.length ,
itemBuilder : (context,index){
return QuizTile(url:snapshort.data.docs[index].data()['url'],
title:snapshort.data.docs[index].data()['title'] ,
desc: snapshort.data.docs[index].data()['desc'],
);
}
);
Since you are reference a collection, then you need to use docs which will retrieve a list of documents inside that collection:
https://github.com/FirebaseExtended/flutterfire/blob/master/packages/cloud_firestore/cloud_firestore/lib/src/query_snapshot.dart#L18
Then to access each field in the document, you need to call data()
The answer by #Peter Haddad is correct. Just to highlight the difference with an example from my own code:
The previous version of code which created the same error:
snapshot.data.docs[index].data["chatRoomID"]
Updated version of code which solved the error:
snapshot.data.docs[index].data()["chatRoomID"]
Updated Version:
snapshot.data[i]['Email'],
Future getRequests() async {
QuerySnapshot snapshot = await FirebaseFirestore.instance.collection("Buyer Requests").get();
return snapshot.docs;
}
body: FutureBuilder(
initialData: [],
future: getRequests(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
indexLength = snapshot.data.length;
if (snapshot.hasData)
return SizedBox(
child: PageView.builder(
itemCount: indexLength,
controller: PageController(viewportFraction: 1.0),
onPageChanged: (int index) => setState(() => _index = index),
itemBuilder: (_, i) {
return SingleChildScrollView(
child: Card(
margin: EdgeInsets.all(10),
child: Wrap(
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage(
'assets/images/shafiqueimg.jpeg'),
),
title: Text(
snapshot.data[i]['Email'],
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
color: Colors.black.withOpacity(0.7),
),
),
subtitle: Text(
snapshot.data[i]['Time'],
style: TextStyle(
color: Colors.black.withOpacity(0.6)),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(5)),
color: Colors.grey[200],
),
padding: EdgeInsets.all(10),
child: Text(
snapshot.data[i]['Description'],
style: TextStyle(
color: Colors.black.withOpacity(0.6)),
),
),
SizedBox(
height: 8,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(5)),
border: Border.all(
color: Colors.grey[300])),
child: ListTile(
leading: Icon(Icons.category_outlined),
title: Text(
'Category : ${snapshot.data[i]['Category']}',
style: TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
),
),
SizedBox(height: 8),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(5)),
border: Border.all(
color: Colors.grey[300])),
child: ListTile(
leading: Icon(Icons.location_pin),
title: Text(
snapshot.data[i]['Location'],
style: TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
),
),
SizedBox(height: 8),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(5)),
border: Border.all(
color: Colors.grey[300])),
child: ListTile(
leading: Icon(
Icons.attach_money,
color: kGreenColor,
),
title: Text(
'Rs.${snapshot.data[i]['Budget']}',
style: TextStyle(
fontSize: 14,
color: kGreenColor,
),
),
),
),
SizedBox(height: 8),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(5)),
border: Border.all(
color: Colors.grey[300])),
child: ListTile(
leading: Icon(Icons.timer),
title: Text(
'Duration : ${snapshot.data[i]['Duration']}',
style: TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
),
),
SizedBox(
height: 35,
),
RaisedButton(
padding: EdgeInsets.symmetric(vertical: 10),
child: Text('Send Offer'),
textColor: Colors.white,
color: Colors.green,
onPressed: () {
// Respond to button press
},
),
SizedBox(
height: 15,
),
Center(
child: Text(
"${i + 1}/$indexLength",
style: TextStyle(fontSize: 13),
),
),
],
),
),
],
),
),
);
},
),
);
else
return Center(
child: Text("Null"),
);
},
),
Given that you are referencing a collection, you must use docs to acquire a list of the documents included in that collection:
https://github.com/FirebaseExtended/flutterfire/blob/master/packages/cloud firestore/cloud firestore/lib/src/query snapshot.dart#L18
then you must call data() in order to access each field in the document.

Iterate over firebase database nodes flutter

I want to iterate through the customers available and get the posts of every customer and show it inside a listview.
However, if i specify the database reference as final postsRef = FirebaseDatabase.instance.reference().child('Customers available').child(Uid).child('Posts').orderByChild('timestamp');, I get only the user's posts.
Below is my code for building the listview and another is my database reference. Thanks final postsRef = FirebaseDatabase.instance.reference().child('Customers available')
This is my Firebase Database Screenshot
future: postsRef.once(),
builder: (context, AsyncSnapshot<DataSnapshot> snapshot) {
if (snapshot.hasData) {
lists.clear();
Map<dynamic, dynamic> values = snapshot.data.value;
values.forEach((key, values) {
lists.add(values);
});
return new ListView.builder(
shrinkWrap: true,
itemCount: lists.length,
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.grey[200]))
),
padding: EdgeInsets.all(SizeConfig.blockSizeHorizontal * 4),
child: Row(
children: <Widget>[
Container(
height: 50,
width: 50,
child: Container(
height: 50,
width: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(150),
image: DecorationImage(image: FirebaseImage('gs://tipy-98639.appspot.com/profile_pic'))
),
),
decoration: BoxDecoration(
color: Colors.grey,
image: DecorationImage(image: AssetImage('images/dp.png')),
borderRadius: BorderRadius.circular(150)
),
),
SizedBox(width: SizeConfig.blockSizeHorizontal * 3,),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('NAME', style: TextStyle(
fontFamily: 'myriadpro',
fontWeight: FontWeight.bold,
fontSize: SizeConfig.blockSizeVertical * 1.7
),),
SizedBox(height: SizeConfig.blockSizeVertical * 1,),
Text(lists[index]["text"],
maxLines: 20,
overflow: TextOverflow.clip,
style: TextStyle(
fontFamily: 'myriadpro',
fontSize: SizeConfig.blockSizeVertical * 1.7
),),
],
),
),
],
),
);
});
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(Colors.green),),
Text('Loading your posts... 🕑',
style: TextStyle(
fontFamily: 'myriadpro'
),
)
],
));
}),`

How to get data from other collection in streambuilder

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,
);
},
),

Resources