Migrate Flutter app: realtime db to firestore - firebase

I am migrate flutter app from Firebase realtime database to firestore. I have trouble with update this code in chat app because firestore no have FirebaseAnimatedList.
Old code:
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(“chat“),
),
body: new Container(
child: new Column(
children: <Widget>[
new Flexible(
child: new FirebaseAnimatedList(
query: reference,
sort: (a, b) => b.key.compareTo(a.key),
padding: new EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (_, DataSnapshot snapshot,
Animation<double> animation, int x) {
return new ChatMessage(
snapshot: snapshot, animation: animation);
},
),
),
New code (but give me errors):
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(“chat"),
),
body: new Container(
child: new Column(
children: <Widget>[
new Flexible(
child: new StreamBuilder<QuerySnapshot>(
stream: reference.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
return snapshot.hasData? new ListView(
physics: const AlwaysScrollableScrollPhysics(),
reverse: true,
padding: new EdgeInsets.all(8.0),
children: snapshot.data.documents.map(DocumentSnapshot snapshot) {
return new ChatMessage(
snapshot: snapshot,
animation: animation,
);
})
),
reference:
final reference = Firestore.instance.collection('messages');
Any help?
I have look up:
Firestore StreamBuilder with nested AnimatedList
How to bind a Firestore documents list to a Dropdown menu in Flutter?
How to listen for document changes in Cloud Firestore using Flutter?
Update:
Thanks everyone for response! I make some changes.
New code:
child: new StreamBuilder<QuerySnapshot>(
stream: reference.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text('loading...');
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot snapshot) {
return new ChatMessage(
snapshot: snapshot,
animation: animation,
);
}).toList(),
);
}
),
),
Now only error is in animation. I have error: undefined name 'animation'

try using ListView.builder ..
new Flexible(
child: new StreamBuilder<QuerySnapshot>(
stream: reference.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
return ListView.builder(
itemCount: snapshot.data.documents.length,
reverse: false,
shrinkWrap: true,
itemBuilder: (context, index) {
return ChatMessage(
animation, snapshot.data.documents[index], index);
});
}))

Missing a bracket:
children: snapshot.data.documents.map((DocumentSnapshot snapshot) {

Related

Listview builder using with future builder with data from firestore

I am trying to use FutureBuilder to build some LisTiles with ListView.builder. The data is from Firestore.
It looks like the FutureBuilder dont access the ConnectionState.done, because I have this whole time CircularProgressIndicator() showing.
var qn;
Future<QuerySnapshot> getChargingHistory() async {
await users
.doc('$currentUser')
.collection('chargingHistory')
.get()
.then((QuerySnapshot querySnapshot) {
qn = querySnapshot;
qn.docs.forEach((doc) {
print(doc['Endzeit']);
});
});
setState(() {
});
return qn;
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Hero(
tag: 'logo',
child: Image.asset(
'assets/images/rz_bildmarke_meyer-technik_rgb.png',
height: MediaQuery.of(context).size.height * 0.05,
fit: BoxFit.cover,
),
),
actions: [],
centerTitle: true,
elevation: 4,
),
body: BackgroundContainer(
child: Column(
children: [
Expanded(
child: FutureBuilder(
future: getChargingHistory(),
builder: (context, querySnapshot) {
if (querySnapshot.connectionState ==
ConnectionState.done) {
return ListView.builder(
itemCount: qn.docs.length,
itemBuilder: (BuildContext context, index) {
return ListTile(
title: Text('${qn.docs.data['Endzeit'].toString()}'));
//Text(doc['Endzeit']);
}
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
),
First, you are mixing async/await with .then. You don't need var qn;, simply return the result of await from your getChargingHistory, like:
Future<QuerySnapshot> getChargingHistory() async {
return await users
.doc('$currentUser')
.collection('chargingHistory')
.get();
}
Second, you have to use index in itemBuilder to get the data for the current ListTile. Try:
return ListView.builder(
itemCount: querySnapshot.docs.length,
itemBuilder: (BuildContext context, index) {
return ListTile(title:
Text('${querySnapshot
.docs[index]['Endzeit'].toString()}'));
Instead of using querySnapshot.connectionState==ConnectionState.done, try using querySnapshot.hasData==true.

How to retrieve data from Firebase Realtime to the flutter app in a lisview

I am looking to retrieve data stored in Firebase Realtime database and display it in a new page in a lisview, how can I achieve that. So far I can retrieve and print it out in a console terminal.
My code is below:
class BarcodesResultPreviewWidget extends StatelessWidget {
FirebaseDatabase.instance.reference().child('ScannedResults');
body: Column(
children: <Widget>[
previewView,
//printing scanned results
Expanded(
child: ListView.builder(
itemBuilder: (context, position) {
return BarcodeItemWidget(preview.barcodeItems[position]);
},
itemCount: preview.barcodeItems.length,
),
),
FlatButton(
color: Colors.grey,
child: Text('Save',),
onPressed: () {
databaseRef.push().set({
'ScannedItem': preview.barcodeItems
.map((barCodeItem) => barCodeItem.toJson())
.toString(),
});
},
),
To fetch the data into a new page and build listview, try something like this:
return Scaffold(
body: FutureBuilder(
future: databaseRef.once(),
// future: FirebaseDatabase.instance
// .reference()
// .child("ScannedResults")
// .once(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return new Text('Loading....');
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
List scannedItemsValues = [];
snapshot.data.value.forEach(
(_, values) => scannedItemsValues.add(values["ScannedItem"]));
print(scannedItemsValues);
return ListView.builder(
itemCount: scannedItemsValues.length,
itemBuilder: (BuildContext context, int index) {
// build your listView here
print(scannedItemsValues[index]);
return Text(scannedItemsValues[index]);
},
);
},
),
);

How to display data in listview using StreamBuilder from Realtime DB in flutter

I am developing an app for my college project and I am stuck in an error. I am using realtime DB to store data. I am Using a listView to display all the availble data in the db.
When ever I try to retrieve data from DB if the data is available then it gets loaded. But, if there is no data available(I mean If the PlantData is not available) Then it Shows this error
This is my Code
final dbRef = FirebaseDatabase.instance
.reference()
.child("IDh04V383uYGQQfWlVWp2XsdR0J3")
.child("PlantData");
List lists = List();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: StreamBuilder(
stream: dbRef.onValue,
builder: (context, AsyncSnapshot<Event> snapshot) {
if (snapshot.hasData) {
print("Error on the way");
lists.clear();
DataSnapshot dataValues = snapshot.data.snapshot;
Map<dynamic, dynamic> values = dataValues.value;
values.forEach((key, values) {
lists.add(values);
});
return new ListView.builder(
shrinkWrap: true,
itemCount: lists.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Name: " + lists[index]["smartID"]),
Text("Image: " + lists[index]["plantname"]),
],
),
);
},
);
}
return Container(child: Text("Add Plants"));
},
),
),
);
As #Uni mentioned you can provide the initialData to your StreamBuilder but I would also recommend to always write your code to be prepared for every case the state can have like so:
final dbRef = FirebaseDatabase.instance
.reference()
.child("IDh04V383uYGQQfWlVWp2XsdR0J3")
.child("PlantData");
List lists = List();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: StreamBuilder(
stream: dbRef.onValue,
builder: (context, AsyncSnapshot<Event> snapshot) {
if (snapshot.hasData && !event.hasError &&
event.data.snapshot.value != null) {
print("Error on the way");
lists.clear();
DataSnapshot dataValues = snapshot.data.snapshot;
Map<dynamic, dynamic> values = dataValues.value;
values.forEach((key, values) {
lists.add(values);
});
return new ListView.builder(
shrinkWrap: true,
itemCount: lists.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Name: " + lists[index]["smartID"]),
Text("Image: " + lists[index]["plantname"]),
],
),
);
},
);
}
return Container(child: Text("Add Plants"));
},
),
),
);
You should also handle the state when your data is loading and also when you have an error. That way you should not get any surprises.

Retrieve collection of certain firebase document in flutter

the document name is the auth user but i cant retrive it as index in the firestore i only need to point at the user.uid and retrieve its collection
StreamBuilder(
stream: Firestore.instance.collection("Attendees").snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return new ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
padding: const EdgeInsets.only(top: 5.0),
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.documents[index];
return new Row(
textDirection: TextDirection.ltr,
children: <Widget>[
Expanded(child: Text(ds['absenceDay'])),
Expanded(child: Text(ds['excuse'])),
],
);
});
}
},
)
Try the following:
getDocument() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
return Firestore.instance.collection("Attendees").document(user.uid).snapshots();
}
Then use it in StreamBuilder:
StreamBuilder(
stream: getDocument(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {

Gridview.builder with Firebase realtime database and futurebuilder

Coming from Firestore, I am a little bit struggling how to receive data from Firebase real time database. I just want a nice grid view of images which are loaded from the realtime database.
Error: flutter: The following NoSuchMethodError was thrown building:
flutter: Class 'DataSnapshot' has no instance method '[]'.
flutter: Receiver: Instance of 'DataSnapshot'
I guess it's index related. No idea how to correctly map it within a list.
import 'package:cached_network_image/cached_network_image.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(16.0),
child: new FutureBuilder(
future: FirebaseDatabase.instance
.reference()
.child('messages')
.child('1551276762582')
.orderByChild('messagetype')
.equalTo('1')
.once(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
if (snapshot.data != null) {
return new Column(
children: <Widget>[
new Expanded(
child: new GridView.builder(
// itemCount: item.length,
gridDelegate:
new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2),
itemBuilder: (context, index) {
return GridTile(
child: CachedNetworkImage(
imageUrl: snapshot.data[index]['imageUrl']
.toString()));
},
),
)
],
);
} else {
return new CircularProgressIndicator();
}
} else {
return new CircularProgressIndicator();
}
}));
}
}
I could solve it with the following code. Again, I have to say that the Firebase documentation really lacks, which is quite disappointing, since Firebase is a great tool. Moreover, I do not understand, that there is no documentation on 'How to use Firebase with Flutter' (we are talking about both Google products.) Notwithstanding, here is the working code for anyone, who likes to use Streambuilder with Gridview.builder with the Realtime Database in Flutter:
StreamBuilder(
stream: FirebaseDatabase.instance
.reference()
.child('messages')
.child(groupId)
.orderByChild('messagetype')
.equalTo(1)
.onValue,
builder: (BuildContext context, AsyncSnapshot<Event> snapshot) {
if (snapshot.hasData) {
if (snapshot.data.snapshot.value != null) {
Map<dynamic, dynamic> map = snapshot.data.snapshot.value;
List<dynamic> list = map.values.toList()
..sort(
(a, b) => b['timestamp'].compareTo(a['timestamp']));
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
itemCount: list.length,
padding: EdgeInsets.all(2.0),
itemBuilder: (BuildContext context, int index) {
return Container(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondScreen(
imageUrl: list[index]["imageUrl"])),
);
},
child: CachedNetworkImage(
imageUrl: list[index]["imageUrl"],
fit: BoxFit.cover,
),
),
padding: EdgeInsets.all(2.0),
);
},
);
} else {
return Container(
child: Center(
child: Text(
'Es wurden noch keine Fotos im Chat gepostet.',
style: TextStyle(fontSize: 20.0, color: Colors.grey),
textAlign: TextAlign.center,
)));
}
} else {
return CircularProgressIndicator();
}
})),
Something that I do that helps me solve issues, is by explicitly turning snapshots into Maps the following way.
Map yourModel = Map.from(datasnapshot);
also many times when handling null data or so on I have to turn the asyncSnap value that comes from the future Builder into a Datasnapshot from firebase in the following way
Datasnapshot snap = asyncSnap.data;
then handle for snap being null
if(snap.value!=null){}
Hope this helps! if you need help send me a message

Resources