'How to get data from database and into listview.builder
I am trying to get data from Firebase RTDB and then display them as a list using Listview.builder.
This worked well before, however I have added a new node into my database to have it be more stuctured. The problem is, inspite of there being data, it's showing up as empty when I try to retrieve it.
Code:
Future<List> getParentDetails() async {
schoolName = await getSchoolName();
databaseReference
.child("users")
.child(schoolName.toString()) // 👈👈👈(newly added)
.child("parents")
.onValue
.listen(
(event) {
if (event.snapshot.exists) {
setState(
() {
var value = event.snapshot.value;
parentList = Map.from(value)
.values
.map((e) => Parents.fromJson(Map.from(e)))
.toList();
},
);
} else {
print("No Data Exists");
}
},
);
return parentList;
}
UI Code:
ListView.builder(
itemCount: parentList.length,
itemBuilder: (context, int index) {
final Parents parents = parentList[index];
final String parentEmail = parents.email;
final String parentName = parents.name;
final String parentPhone = parents.phone;
// final String parentUID = parents.uid;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 0.2,
child: ExpansionTile(
// collapsedBackgroundColor: Colors.grey,
title: Text(
parentName.toUpperCase(),
style: GoogleFonts.lexendMega(
fontSize: 12,
),
textAlign: TextAlign.center,
),
children: [
Column(
children: [
Text(
parentEmail,
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(fontSize: 12),
),
SizedBox(
height: 5,
),
Text(
parentPhone,
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(fontSize: 12),
),
SizedBox(
height: 5,
),
],
)
],
),
),
);
},
),
New Edit:
getSchoolName() async {
// ignore: unused_local_variable
final ref = FirebaseDatabase.instance.reference();
User user = auth.currentUser;
String adminUID = user.uid.toString();
print("Getting School Name");
databaseReference.child("users").child("admin").child(adminUID).once().then(
(DataSnapshot snapshot) {
setState(() {
schlName = snapshot.value["school"];
print(schlName); // 👈👈👈 (Prints - Highway Secondary School)
});
},
);
return await schlName;
}
Future<List> getParentDetails() async {
schoolName = await getSchoolName();
databaseReference
.child("users")
.child("Highway Secondary School")
.child("parents")
.onValue
.listen(
(event) {
if (event.snapshot.exists) {
setState(
() {
var value = event.snapshot.value;
print(value); // 👈👈👈 (See print value below)
parentList = Map.from(value)
.values
.map((e) => Parents.fromJson(Map.from(e)))
.toList();
},
);
} else {
print("No Data Exists");
}
},
);
return parentList;
}
Output:
{L9LnmRTZJgVJWjNhrcTqoRdMlas2: {driver: Locate the driver: , phone: ********, school: Highway Secondary School, name: Parent One, user uid: L9LnmRTZJgVJWjNhrcTqoRdMlas2, email: **********@gmail.com}, Z9nHn3HZ3MZqgS7RsKsFiofD4ty2: {driver: Locate the driver: , phone: ********, school: Highway Secondary School, name: Parent Two, user uid: Z9nHn3HZ3MZqgS7RsKsFiofD4ty2, email: ***********@gmail.com}}
Edit 2:
Future<List> getParentDetails() async {
schoolName = await getSchoolName();
print(schoolName); 👈👈👈 (Prints - null)
var ref = databaseReference.child("users/$schoolName/parents");
var snapshot = await ref.get();
if (snapshot.exists) {
setState(() {
var value = snapshot.value;
parentList = Map.from(value)
.values
.map((e) => Parents.fromJson(Map.from(e)))
.toList();
});
} else {
print("No Data Exists");
}
return parentList;
}
With newly added line of code above, the code doesn't get any data from the database (from the current database).
Without the newly added line of code, I get data from the old database without any issues.
The intention of the new database is to be more organized.
Solution 1:[1]
This will not work:
Future<List> getParentDetails() async {
schoolName = await getSchoolName();
databaseReference
.child("users")
.child("Highway Secondary School")
.child("parents")
.onValue
.listen(
(event) {
if (event.snapshot.exists) {
setState(
() {
var value = event.snapshot.value;
print(value); // ??? (See print value below)
parentList = Map.from(value)
.values
.map((e) => Parents.fromJson(Map.from(e)))
.toList();
},
);
} else {
print("No Data Exists");
}
},
);
return parentList;
}
Calling listen starts an asynchronous process, but your main code continues to run. So your return parentList runs before the parentList = Map.from(value) is ever called. Adding some more print statements will show that in the order of they are output.
You also return a Future, which you can do only once, while listen can be called many times. If you only get about the current value, you should use get() instead of listen as shown in the documentation on reading data once.
With that, the code would look something like:
Future<List> getParentDetails() async {
schoolName = await getSchoolName();
var ref = databaseReference.child("users/Highway Secondary School/parents");
var snapshot = await ref.get();
if (snapshot.exists) {
setState(
() {
var value = snapshot.value;
parentList = Map.from(value)
.values
.map((e) => Parents.fromJson(Map.from(e)))
.toList();
},
);
} else {
print("No Data Exists");
}
return parentList;
}
Update: to also fix getSchoolName it's important to not mix then with async/await, but use one or the other only.
getSchoolName() async {
final ref = FirebaseDatabase.instance.reference();
User user = auth.currentUser;
String adminUID = user.uid.toString();
var snapshot = databaseReference.child("users/admin").child(adminUID).get();
schlName = snapshot.value["school"];
setState(() {});
return schlName;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |


