I am able to successfully create a listview.builder in flutter application as per the below code.
CODE
Container(
child: StreamBuilder<QuerySnapshot>(
stream: query2.snapshots(),
builder: (BuildContext context,AsyncSnapshot<QuerySnapshot> snapshot) {
var usernames = snapshot.data.docs.map((e) => e['itemName']);
print("usernames");
print(usernames);
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index){
// String itemname =snapshot.data.docs[index]['itemName'] ?? "";
return ListTile(title:Text(snapshot.data.docs[index]['itemName'] ?? ""
),);
});
}
),
)
But I want to have list view builder to be created on about 5 different if-else conditions which I am not able to do so, I tried to implement this thing on StreamBuilder but could not do it, though ternary operator works but for only two conditions at at time and not multiple conditions, how should I achieve it?
this is very simple.
if(condition1)
return Container(color:Colors.blue);
else if(condition2)
return Container(color:Colors.yellow);
else if(condition3)
return Container(color:Colors.green);
else if(condition4)
return Container(color:Colors.red);
...etc.
else
return SizedBox();
Related
I have this problem in flutter :
I want to return a different page accordingly to a specific result after doing some functions.
Some functions are asynchronous :
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (ctx, userSnapshot) {
if (userSnapshot.hasData) {
return FutureBuilder(
future: getCurrentUser(),
builder: (ctx, snapshot){
if(snapshot.hasData)
{
return CheckPermission();
} else if (userSnapshot.hasError) {
return CircularProgressIndicator();
}
return RegistrationPage();
},
); // FutureBuilder
} else if (userSnapshot.hasError) {
return CircularProgressIndicator();
}
return LoginPage();
},
),// StreamBuilder
The getCurrentUser function is async, but the FutureBuilder don't wait to get some data from this function, it continue executing and return the RegistrationPage and after a while the data come to FutureBuilder and then it wants to return the CheckPermission page but the build of RegistrationPage is already beginning so : Error.
If anyone has an idea to solve this.
Thanks.
I tried this to discover the problem :
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (ctx, userSnapshot) {
if (userSnapshot.hasData) {
return FutureBuilder(
future: getCurrentUser(),
builder: (ctx, snapshot){
if(snapshot.hasData)
{
return Text('has Data');
} else if (userSnapshot.hasError) {
return CircularProgressIndicator();
}
return Text('No Data');
},
);
} else if (userSnapshot.hasError) {
return CircularProgressIndicator();
}
return LoginPage();
},
),
I replace the pages by some dummy Text() widgets.
The Text('No Data') is visible and after a while, the Text('has Data') is taking the place instead of Text('No Data').
It means that the function is not waiting for the Data even it's marked with async and wait.
In your FutureBuilder, try adding a ConnectionState check like this:
FutureBuilder(
future: getCurrentUser(),
builder: (ctx, snapshot) {
// Add this
if (snapshot.connectionState == ConnectionState.waiting) return CircularProgressIndicator();
if (snapshot.hasData) {
return CheckPermission();
} else if (userSnapshot.hasError) {
return CircularProgressIndicator();
}
return RegistrationPage();
},
); /
I'm Getting blank Spaces in GridView.builder while displaying data from snapshots. I think its because I have applied condition inside GridView.builder so its leaving blank spaces. Is there any way to overcome this ?
StreamBuilder(
stream: fireStore,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3,
mainAxisExtent: MediaQuery.of(context).size.width/1.5),
itemCount: snapshot.data?.docs.length,
itemBuilder: (context, index) {
if (snapshot.data?.docs[index]["userType"] == "1" &&
snapshot.data?.docs[index]["about"] != "") {
return cardWidget(snapshot, index);
} else {
return SizedBox.shrink();
}
},
);
},
);
The problem is that you are still returning an empty Widget (SizedBox.shrink()), that's why it is rendered as empty space. What you need to do is, prepare the valid data before returning the GridView widget.
e.g
final validData = snapshot.data?.docs.where((d)=> d['userType']==1 && d['about']!= 'data').toList();
Now you can use the validData to feed your GridView instead of snapshot.data?.docs.
I'm making a to-do list with Flutter and Firebase Firestore, but I have a slight problem. Whenever I add a new task, snapshot.data becomes null. If I do not add a check for snapshot.connectionState and render a different widget according to that, I get the following error: NoSuchMethodError (NoSuchMethodError: The getter 'docs' was called on null.
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('tasks')
.doc(widget.uid)
.collection('mytasks')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: SizedBox(
height: 100, width: 100, child: CircularProgressIndicator()),
);
} else {
> final docs = snapshot.data.docs;
return ListView.builder(
itemCount: docs.length,
itemBuilder: (ctx, index) {
final currTask = docs[index];
return Dismissible(
direction: DismissDirection.startToEnd,
key: UniqueKey(),
onDismissed: (_) async {
FirebaseFirestore.instance
.collection('tasks')
.doc(widget.uid)
.collection('mytasks')
.doc(currTask['id'])
.delete();
.
.
.
I don't want to have to display a CircularProgressIndicator or an empty screen. I want the tasks to remain visible and seamlessly add new tasks. How can I achieve that? I know what I asked for in the question title might be a little silly, what should I do instead?
The relevant error-causing widget was
StreamBuilder. I've given the link of the project repo in github .
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection("/chats/2DGQmBssJ4sU6MVJZYc0/messages")
.orderBy('createdAt', descending: true)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
Center(child: CircularProgressIndicator());
final documents = snapshot.data.documents;
return ListView.builder(
reverse: true,
itemCount: documents.length,
itemBuilder: (context, index) {
return MessageBubble(
documents[index]['text'],
documents[index]['userID'] == user.uid,
documents[index]['userID'],
documents[index]['imageurl']);
},
);
},
);
}
}
Github link of the project
Try the following:
if (snapshot.connectionState == ConnectionState.waiting)
Center(child: CircularProgressIndicator());
else if(snapshot.connectionState == ConnectionState.active){
final documents = snapshot.data.documents;
return ListView.builder(
reverse: true,
itemCount: docs.length,
itemBuilder: (context, index) {
return MessageBubble(
docs[index]['text'],
docs[index]['userID'] == user.uid,
docs[index]['userID'],
docs[index]['imageurl']);
},
);
},
},
);
When the connectionState is active meaning with data being non-null, then retrieve the data. Also use docs since it seems you are using the new version of Firestore.
documents became docs
Edit
Now that I've become little better than before, so I must update this answer for better understanding.
Let's take this above example:
return ListView.builder(
reverse: true,
itemCount: documents.length,
itemBuilder: (context, index) {
return MessageBubble(
documents[index]['text'],
documents[index]['userID'] == user.uid,
documents[index]['userID'],
documents[index]['imageurl']);
},
);
},
);
Here, all the documents in that particular collection MUST contain these 3 fields, i.e, 'text', 'userID', and 'imageurl' to successfully build each child inside the listView.builder().
But, if any of these 3 fields is missing, or even miss-spelled in One or more documents, then it would throw an error like the above.
Will throw error:
Will throw error:
So, to solve that we need to find that particular document which has the field missing, or field miss-spelled and correct it.
Or, delete that document and keep only those documents which has correct fields.
(By the way, I'm using "Dark Reader" chrome extension for dark theme for firebase console, and every other website on internet.)
My Old Answer:
In my case I was using Firebase Firestore for my chat app, and while loading the chat screen, I was getting this error.
So in Firestore Database I had 15-20 messages, So I deleted most of them and leave just 2-3 messages. And then the Error disappeared.
I don't know happened here.
You create a widget and then don't use it and follow through with the rest of your logic:
if (snapshot.connectionState == ConnectionState.waiting)
Center(child: CircularProgressIndicator());
You need to stop there and return that widget from your builder:
if (snapshot.connectionState == ConnectionState.waiting)
return Center(child: CircularProgressIndicator());
Here, I'm trying to print the username of the user and it produces the following error.
I created a function userData() and the code is
userData() async
{
var userData = await _db.collection('users').document(_uuid).get();
return userData;
}
Where I'll just get the data of the specific user using uid and returning it.
The code I used to print the data is as follow
return FutureBuilder(
future: authService.userData(),
builder: (_,snapshots){
if(snapshots.connectionState == ConnectionState.waiting)
{
return Center(child: Text('Loading...'),);
}
else{
print("Snapshots: "+snapshots.toString());
return ListView.builder(itemCount: 1, itemBuilder: (_,index){
return ListTile(
title: Text(snapshots.data["username"].toString()),
);
});
}
}
);
The structure of firestore is
Collection('user') -> document(uid) -> 1.username 2.email ....
What is the reason for this error and how to resolve it?
The error message is telling you that snapshots.data is null, so you can't index into it with the [] operator.
Before using a DocumentSnapshot, you should check to see if it exists before accessing its field data. The snapshot's data property will be null if the document doesn't exist.
For Firestore I would recommend using Stream Builder rather than future Builder.
return StreamBuilder(
stream: Firestore.instance
.collection('user')
.document(uid)
.snapshots(),
builder: (_,snapshot){
if(!snapshot.hasData)
{
return Center(child: Text('Loading...'),);
}
else{
return ListView.builder(itemCount: 1, itemBuilder: (_,index){
return ListTile(
title: Text(snapshots.data["username"].toString()),
);
});
}
}
);