Unable to retrieve firebase data to Listview - firebase

I am trying to retrieve data from my real-time firebase into a listview.
The Firebase Json Tree:
I want to retrieve Item, Expiry Date and Quantity in the listview format.
My code is as follows:
var lists = [];
final database = FirebaseDatabase(
databaseURL: "https://trackkit-a5cf3-default-rtdb.asia-southeast1.firebasedatabase.app")
.reference()
.child('Location 1');
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: StreamBuilder(
stream: database.onValue,
builder: (context, AsyncSnapshot<Event> snapshot) {
if (snapshot.hasData && !snapshot.hasError &&
snapshot.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 ListView.builder(
shrinkWrap: true,
itemCount: lists.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Item: " + lists[index]["Item"]),
Text("Expiry Date: " + lists[index]["Expiry Date"]),
Text("Quantity: " + lists[index]["Quantity"]),
],
),
);
},
);
}
return Container(child: Text("Add Items"));
},
),
),
);
}
The current screen shows :
type 'int' is not a subtype of type 'String'
I have been trying for days! Any help would be greatly appreciated.

Maybe you are getting a Integer value in return to your lists[index]["Quantity"]. And you cannot concat and integer with String without converting into a String.
So Please use method toString() with lists[index]["Quantity"] to make it work properly.

You have to Quantity make a String value, use toString() method on it in Text Widget,
like that: Text("Quantity: " + lists[index]["Quantity"].toString())

Related

Is there anyway to sort incoming data from StreamBuilder?

Stream<QuerySnapshot> _usersStream = FirebaseFirestore.instance.collection('Listings').snapshots();
I am using this stream.
And i have streambuilder like this.
Flexible(
child: StreamBuilder<QuerySnapshot>(
stream: _usersStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Error');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
String start_location=data['start_location'];
String end_location=data['end_location'];
String date=data['date'];
String time=data['time'];
String price=data['price'];
String name_surname=data['name_surname'];
String userId=data['user_id'];
String coord=data['coord'];
var splitted=coord.split('/');
for(int i=0; i<splitted.length-1; i++){
String x = splitted[i];
var splitted2=x.split('-');
double result=calculateDistance(widget.place_latlng.latitude, widget.place_latlng.longitude, double.parse(splitted2[0]), double.parse(splitted2[1]));
if(result<1 && start_location!= widget.placename){
print("Found!");
return GestureDetector(
onTap: (){
//onTap func
},
child: buildTripCard(
context,
start_location: start_location,
end_location: end_location,
date: date,
time: time,
price: price,
name_surname: name_surname,
userId: userId,
),
);
}
}
return Container();
}).toList(),
);
},
),
)
I put into the incoming data to calculateDistance function. It returns double value (result).If that value less than 1, it shows in ListView. What i want to do is, sort Data which shows in listView order by result value.
How can i reach list that i created with .toList() method?
Sort data by chaining into stream. The below example takes all photos, which title starts with p. Converting Future to Stream is just for demonstration.
Stream<List<Photo>> photos() {
return Stream.fromFuture(
http.get(Uri.parse('https://jsonplaceholder.typicode.com/photos'))
).map((r) => parsePhotos(r.body))
.map((list) => list.where((p) => p.title.startsWith('p')).toList());
}
Then use ListView.builder to render the final list.
StreamBuilder<List<Photo>>(
stream: photos(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text('An error has occurred!'),
);
} else if (snapshot.hasData) {
final photos = snapshot.data!;
return ListView.builder(
itemCount: photos.length,
itemBuilder: (context, index) {
return Text(photos[index].title);
},
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
}

How to create streambuilder and listview with Firebase Realtime database data (Flutter chat app)

I'm building a flutter chat app for my personal learning project where the data will be retrieved from Firebase Realtime database.
I got this code from a tutorial but it is showing errors. How to solve this?
StreamBuilder(
stream: dbRef.onValue,
builder: (context, snapshot) {
if (snapshot.hasData) {
print("Error on the way");
messages.clear();
DataSnapshot dataValues = snapshot.data.snapshot; //Error: The getter snapshot is not defined for the type 'Object';
Map<dynamic, dynamic> values = dataValues.value;
values.forEach((key, values) {
messages.add(values);
});
return new ListView.builder(
shrinkWrap: true,
itemCount: messages.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Name: " + messages[index]["Text"]),
Text("Time: " + messages[index]["TextTime"]),
],
),
);
},
);
}
},
),
This solved the problem.
StreamBuilder(
stream: _dbRef.onValue,
builder: (context, snapshot) {
List<Message> messageList = [];
if (snapshot.hasData &&
snapshot.data != null &&
(snapshot.data! as DatabaseEvent).snapshot.value !=
null) {
final myMessages = Map<dynamic, dynamic>.from(
(snapshot.data! as DatabaseEvent).snapshot.value
as Map<dynamic, dynamic>); //typecasting
myMessages.forEach((key, value) {
final currentMessage = Map<String, dynamic>.from(value);
messageList.add(Message(
author: currentMessage['Author'],
authorId: currentMessage['Author_ID'],
text: currentMessage['Text'],
time: currentMessage['Time'],));
}); //created a class called message and added all messages in a List of class message
return ListView.builder(
reverse: true,
itemCount: messageList.length,
itemBuilder: (context, index) {
return ChattingDesign(
message: messageList[index],
dbpathToMsgChnl:
'TextChannels/${widget.channels['ChannelName']}/Messages',
showName: shouldShowName(
index,
messageList.length - 1,
messageList,
),
);
},
);
} else {
return Center(
child: Text(
'Say Hi...',
style: TextStyle(
color: Colors.white,
fontSize: 21,
fontWeight: FontWeight.w400),
),
);
}
},
),
According to the DataSnapshot Class Documentation there is no field called snapshot
I think there is a typo in your code.
Try this
StreamBuilder(
stream: dbRef.onValue,
builder: (context, snapshot) {
if (snapshot.hasData) {
print("Error on the way");
messages.clear();
DataSnapshot dataValues = snapshot.data! as DataSnapshot ; //here's the typo;
Map<dynamic, dynamic> values = dataValues.value;
values.forEach((key, values) {
messages.add(values);
});
return new ListView.builder(
shrinkWrap: true,
itemCount: messages.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Name: " + messages[index]["Text"]),
Text("Time: " + messages[index]["TextTime"]),
],
),
);
},
);
}
},
),

data in StreamBuilder keeps returning null outside of Firebase RTDB get() call

For some reason, my data variable keeps returning null outside of my .get() call. Within the .get() call, when I print data, I get the expected map. Any insight is appreciated! The part of the code that is giving me issues are in asterisks.
class _MessagesScreenState extends State<MessagesScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
),
child: StreamBuilder(
stream: rtdb
.child('messages')
.child(widget.currentUserID)
.onValue,
builder: (context, snapshot) {
final messageList = <BuildMessages>[];
if (snapshot.hasData) {
final users = Map<String, dynamic>.from(
snapshot.data.snapshot.value);
users.forEach((key, value) {
**var data;**
**usersRef.child(key).get().then((value) {
data = new Map<String, dynamic>.from(value.value);
});**
final messageTile = BuildMessages(
name: data['userFirstName'] +
' ' +
data['userLastName'],
picture: data['userImageUrl'],
otherID: data['userID'],
);
;
messageList.add(messageTile);
});
}
return ListView.builder(
padding: EdgeInsets.only(top: 15.0),
itemCount: messageList.length,
itemBuilder: (context, index) {
return messageList[index];
},
);
}),
),
),
],
),
);
}
That is the expected behavior. The usersRef.child(key).get() returns a Future<DataSnapshot?>, so you'll need to wrap it into a FutureBuilder to use its value.
Based on this answer that'd be something like:
FutureBuilder<DataSnapshot?>(
future: usersRef.child(key).get(), // async work
builder: (BuildContext context, AsyncSnapshot<DataSnapshot?> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return Text('Loading....');
default:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else
return Text('Result: ${snapshot.data!.value}');
}
},
)

Flutter Firebase - Retrieve array & map data

This is my dataset :
I am trying to get this type of data in my app 1st I use an array and in the array i add map data and my value but i don't get any data.
My code
child: StreamBuilder(
stream: FirebaseFirestore.instance.collection("coin").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Loder();
}
return ListView.builder(
itemCount: snapshot.data.document.length,
itemBuilder: (BuildContext context, int index) {
Map<dynamic, dynamic> map = snapshot.data.documents[index];
return ListTile(
title: Text(map.values.toList()[index]["coinlink"]),
);
},
);
}),
EDIT 1
I got this error I need data from coinlink title and img
The following NoSuchMethodError was thrown building StreamBuilder<QuerySnapshot<Map<String,
dynamic>>>(dirty, state: _StreamBuilderBaseState<QuerySnapshot<Map<String, dynamic>>,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>>>#29591):
Class '_JsonQuerySnapshot' has no instance getter 'document'.
How to get this type of data?
You need column inside list of display multiple coinLinks.
return ListView.builder(
itemCount: snapshot.data.document.length,
itemBuilder: (BuildContext context, int index) {
Map<dynamic, dynamic> map = snapshot.data.documents[index];
final coinLinks = map["coinLink"] as List<Map<String,dynamic>>;
return ListTile(
title: Column(
children: coinLinks.map((coinLink){
return Text(coinLink["title"]);
}).toList()
),
);
},
);

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.

Resources