I followed the chat development app tutorial on the Flutter page, it's a single user app. I have now been able to create a database and store data in the database, but I now have a conundrum that I'm unable to resolve.
I'm loading the chats from the database using FutureBuilder
FutureBuilder(
future: _requestSqlDataAsync(),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(
child: Text("Loading...."),
),
);
}
else {
return ListView.builder(
padding: EdgeInsets.all(8.0),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Text(snapshot.data[index].chat);
}
);
It successfully loads the data from the database but then I'm unable to pass submit new chats from TextController to the display widget in the following manner:
ListView.builder(
padding: EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (_, int index) => _message[index],
itemCount: _message.length,
)
where _message is the widget that combines the data from the TextController along with animation, to display the chat.
Could anyone please guide me as to how I can load the data from the database and then pass the control for the chats to be loaded.
Related
This is my code. Here, I have used Listview.builder due to which whole data is displayed in 1 tablecell. What should I use at place of listview to display the data properly in different cells.
Or Any other way to display data dynamically from backend?
TableRow(children: [
TableCell(
child: FutureBuilder(
future: fetchProducts(),
builder: (context, snapshot){
if(snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
shrinkWrap: true,
itemBuilder: (BuildContext context, index){
Products product = snapshot.data[index];
return Text(//"Name :- "
'${product.pname}', style: TextStyle(fontSize: 15));
});
}},
)),]),
In place of tablerow use DataTable, it will automatically size itself, it has column and row children so its probably the best way to display your data, check this youtube vide out
https://www.youtube.com/watch?v=ktTajqbhIcY&vl=en
I am trying to only display certain data from a collection. In my example, I only want to show data in the list where the collection in name on firebase is equal to the name of the widget. I am unable to solve this problem
Expanded(
child: Container(
child: FutureBuilder(
future: getPosts(),
builder: (_,snapshot){
if(snapshot.data["name"]== widget.info.name){
return ListView.builder(
itemCount:
x,
itemBuilder: (_,index){
return ListTile(
title: Text(snapshot.data[index].data["name"]),
);
});
Expanded(
child: Container(
child: FutureBuilder(
future: getPosts(),
builder: (_,snapshot){
return ListView.builder(
itemCount:
snapshot.data,
itemBuilder: (_,index){
if(snapshot.data["name"]== widget.info.name){
return ListTile(
title:Text(snapshot.data[index].data["name"]),
);
}else{
return Container();
}
})}))
);
A better option will be to pass the widget name in the getPosts() function you defined and update the firebase query to do the filtering. This way it be much faster as firebase does the require indexing and will do the filtering in O(len(filtered_elements)) rather than current time complexity of O(len(all_elements)).
I'm new to flutter and I want to organise the elements that I get from Firestore in a list with StickyHeaders. I would like to do it with an itemBuilder and the snapshot I get from the database.
My problem is the itemBuilder builds each item separately and has to be returned, but StickyHeader needs to have all items added as children.
How can I achieve this? Just as a reference I paste my code without the StickyHeader. buildItemBubble returns a Card Widget.
StreamBuilder(
stream: buildSnapshots(_filters),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Center(
child: CircularProgressIndicator(),
);
return snapshot.data.documents.length == 0
? Center(child: Text('It\s empty here...'))
: CupertinoScrollbar(
child: ListView.builder(
key: new PageStorageKey('randomkey'),
shrinkWrap: true,
padding: const EdgeInsets.all(10.0),
itemCount: snapshot.data.documents.length,
itemBuilder: (ctx, i) =>
buildItemBubble(snapshot, i),
),
);
},
)
I have the following widget which builds a to-do list from a subcollection of a task given its document ID. The code is working fine.
Widget buildFoodList() {
return SizedBox(
child: Container(
padding: const EdgeInsets.all(10.0),
child: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('tasks').document(documentID).collection('todo')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text('Loading...');
default:
return new ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.documents[index];
return new Row(
children: <Widget>[
Expanded (child:Text(ds['deadline'].toString()) ),
Expanded (child:Text(ds['description']) ),
Expanded (child:Text("\$"+ds['quantity'].toString()) ),
],
);
},
);
}
},
)
),
);
}
As you can see, I am using a StreamBuilder. However, I know that the subcollection is not going to change. So the question is whether using StreamBuilder is an overkill, because using stream to listen can be a waste of resources and access to Firebase. More importantly, the cost of using Firebase is calculated on an access basis.
To summarise, the question is whether using StreamBuilder is necessary. If not, what is the alternative approach which can help to avoid unnecessary access to Firebase.
Thanks.
StreamBuilder is necessary in apps where you need to fetch any update , insert or delete in a firebase collection ( in this case ). An alternative can be the FutureBuilder that fetch the data once and then you can wrap in a Swipe to refresh ( and the user decides when needs to see new data).
I'm trying to create a nested ListView, but don't know, if I can combine 2 streambuilders in a nested view, as it doesn't work. In the second StreamBuilder with the subcollection query, no data seems to be returned and I can't figure out why.
When I hardcode the document id I don't get any error, but still the query doesn't seem to return any data.
Does anybody know, how to construct a nested listview with streambuilders and Firestore?
List<Widget> buildStreamedListView() {
return [ StreamBuilder(
stream: Firestore.instance.collection('course')
.document(widget.data.documentID)
.collection('section')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text("Loading...");
return Expanded(child: ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
//return buildListItem(context, snapshot.data.documents[index]);
return Card(
child: ExpansionTile(
title: Text(snapshot.data.documents[index]['name']),
children: <Widget>[
StreamBuilder(
stream: Firestore.instance.collection('course')
.document(widget.data.documentID)
.collection('section')
.document('4CjAZEQ416NYpu3ra3OE')
.collection('page')
.snapshots(),
builder: (context, snap) {
return ListView.builder(
shrinkWrap: true,
itemCount: snap.data.documents.length,
itemBuilder: (context, index) {
return Text('Hello you');
}
);
}
),
],
),
);
}
));
},
)];
}
The reason that I had strange errors was, that in the second builder function I didn't add the following code:
if (!snapshot.hasData) return const Text("Loading...");
Once I added it, it worked. Seems the data was just not ready yet, hence it couldn't be read and hence the error.
Be careful to also test for snap.hasData() in your nested StreamBuilder.