_FutureBuilderState<dynamic>The getter 'length' was called on null. Receiver: null Tried calling: length - flutter

My method getting the data from db and displaying on the console. I tried several hints given in the other posts as well with no luck.
_getUsers() async {
print("getting");
var data = await http.post("http://10.0.2.2/Flutter/getdata.php", body: {
"date": formattedDate,
});
var jsonData = json.decode(data.body);
print(jsonData);
}
However the future builder not able to display:
new FutureBuilder(
future: _getUsers(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return Center(
child: new Text('Error ${snapshot.error}'),
);
} else {
return Center(
child: Padding(
padding: const EdgeInsets.fromLTRB(56.0, 8.0, 56.0, 8.0),
//Here I guarded against the null as well:
child: ListView.builder(
itemCount: snapshot.data.length == null // showing error here
? 0
: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: new Text(
'${snapshot.data[index]["branch"]}',
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
),
),
trailing: new Text(
'${snapshot.data[index]["count(`branch`)".toString()]}',
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
),
),
);
}),
),
);
}
}),
How can I solve the issue?

you should return jsonData in _getUser().
getUsers() async {
print("getting");
var data = await http.post("http://10.0.2.2/Flutter/getdata.php", body: {
"date": formattedDate,
});
var jsonData = json.decode(data.body);
return jsonData;
}
, and change this
itemCount: snapshot.data.length == null // showing error here
? 0
: snapshot.data.length,
to this
itemCount: snapshot.data?.length ?? 0,
snapshot.data? checks whether the data is null or not. ?? executes its successor when the predecessor is null.

Your function doesn't return any Future, therefore the FutureBuilder is unable to get a Future to run on.
_getUsers() {
print("getting");
return http.post("http://10.0.2.2/Flutter/getdata.php", body: {
"date": formattedDate,
});
}
It needs to return a Future, you shouldn't be using await because the FutureBuilder depends on an actual Future, not data. You obtain the data inside the builder and then decode it.
new FutureBuilder(
future: _getUsers(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return Center(
child: new Text('Error ${snapshot.error}'),
);
} else if (snapshot.hasData) { // checking for data
return Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 56, vertical: 8),
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: new Text(
'${snapshot.data[index]["branch"]}',
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
),
),
trailing: new Text(
'${snapshot.data[index]["count(`branch`)".toString()]}',
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
),
),
);
}),
),
);
}
}),

Related

Display Firestore data as list without using a stream

I am trying to run a query on my Firebase Firestore data and display the results as a list. Typically, when I do this, I use a streambuilder, which updates the results whenever any data is changed. I was wondering how to display the same data only once, without subscribing to a stream. This is my code for the streambuilder, which updates on change.
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('announcements')
.orderBy('date', descending: true)
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshots) {
if (snapshots.connectionState == ConnectionState.active &&
snapshots.hasData) {
return ListView(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
children: snapshots.data!.size == 0
? [
const Padding(
padding: EdgeInsets.only(top: 10),
child: Text(
"You have no announcements",
style: TextStyle(
height: 1.0,
fontFamily: "urwmedium",
color: Color(0xffD5D6D7),
fontSize: 20,
),
),
),
]
: snapshots.data!.docs.map(
(DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return Text(
data['announcementTitle'],
);
},
).toList(),
);
}
return Center(
child: CircularProgressIndicator(
color: CustomColors.textColor,
),
);
},
),
The above code works, but again, it loads information realtime. What would the code be if I wanted it to only load once at opening?
as the StreamBuilder is helpful in order to get stream of your collection snapshots
to get that data only once, use FutureBuilder instead:
FutureBuilder<QuerySnapshot>(
future: FirebaseFirestore.instance
.collection('announcements')
.orderBy('date', descending: true)
.get(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshots) {
if (snapshots.connectionState == ConnectionState.done &&
snapshots.hasData) {
return ListView(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
children: snapshots.data!.size == 0
? [
const Padding(
padding: EdgeInsets.only(top: 10),
child: Text(
"You have no announcements",
style: TextStyle(
height: 1.0,
fontFamily: "urwmedium",
color: Color(0xffD5D6D7),
fontSize: 20,
),
),
),
]
: snapshots.data!.docs.map(
(DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return Text(
data['announcementTitle'],
);
},
).toList(),
);
}
return Center(
child: CircularProgressIndicator(
color: CustomColors.textColor,
),
);
},
),

Switch between streams flutter firebase

I have a class of complains in which there is a field of status. This status can be pending , inprogress, completed , rejected. In UI I have designed buttons to filter complaints on the basis of status.
The issue that I am facing is that when I switch stream on button action. It still contains the data of previous stream.
Can anyone help me to have 2 streams and not either of it contains data of previous stream.
bool _isSwitched = false;
List<Complains> complains = [];
final Stream<QuerySnapshot> _all = FirebaseFirestore.instance
.collection('Complains').orderBy("startTime", descending: true)
.snapshots();
final Stream<QuerySnapshot> _pending = FirebaseFirestore.instance
.collection('Complains').where('status', isEqualTo: 'Pending').orderBy("startTime", descending: true)
.snapshots();
ElevatedButton(onPressed:(){
setState(() {
_isSwitched = !_isSwitched;
complains.clear();
complains2.clear();
});
} , child: Text("Switch Stream"),),
StreamBuilder<QuerySnapshot>(
initialData: null,
stream: _isSwitched?_all:_pending,
builder: (context, snapshot) {
if (snapshot.hasError) {
Text("Error");
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
//length of stream is greater than 0
if (snapshot.data!.docs.length == 0) {
return Center(
child: Text("No Complains"),
);
}
for (var element in snapshot.data!.docs) {
Complains complain = Complains.fromMap(element.data() as Map<String, dynamic>);
_isSwitched?complains.add(complain):complains2.add(complain);
}
return ListView.builder(
itemBuilder: (context, index) {
return InkWell(
onTap: () {
},
child: Card(
margin: EdgeInsets.all(8.0),
elevation: 5,
color: Colors.white70,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0))),
child: Container(
padding: EdgeInsets.all(20),
child:
Column(children: [
Text("Title\n ${complains[index].title}",style: TextStyle(fontStyle: FontStyle.italic),),
Table(
children: [
TableRow(children: [
Text("Name: " ),
Text("Address: "+ complains[index].address.toString(),),
]),
TableRow(children: [
Text("Priority: "+ complains[index].priority.toString(),),
Text("Status: "+complains[index].status.toString(),),
]),
TableRow(children: [
Text("Worker: "+ complains[index].worker.toString(),),
Text("Service: "+ complains[index].service.toString(),),
]),
],
),
],)
),
),
);
},
itemCount: _isSwitched?complains2.length:complains.length,
);
},
),
),

Add OnEmpty Widget to ListView.builder() inside FutureBuilder using flutter?

I am using Flutter to develop small application with floor for the database.
I am getting the data from the database using Future then listing all items in UI using FutureBuild.
This is my code
Getting the data from database:
#Query('SELECT * FROM Doctor')
Future<List<Doctor>> findAllDoctor();
Getting data to UI
Future<List<Doctor>> findAllDoctor() async {
return await database.doctorDao.findAllDoctor();
}
Setting data into FutureBuilder:
return FutureBuilder(
future: findAllDoctor(),
builder: (BuildContext context, AsyncSnapshot<List<Doctor>> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: ListTile(
contentPadding: const EdgeInsets.all(8.0),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${snapshot.data![index].firstName} ${snapshot
.data![index].lastName}"),
Text(
snapshot.data![index].phone,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
],
),
subtitle: Text(
"${snapshot.data![index].address} ${snapshot.data![index]
.nameOfTheClinic}"),
),
);
},
);
} else {
return const Center(child: CircularProgressIndicator());
}
},
);
I want to add new widget that tells me no data if there is no data in the table.

Can't retrieve data from nested object firestore streambuilder listview

I'm new using firestore, so im still trying to understand it.
i had Closets on the inside i had Clothes. i want to retrieve Clothes data and show it with listview.
the problem is i failed to retrieve the data and show it into the app
this is my code for the streambuilder
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection("clothes").snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Failed to load data!");
}
if (snapshot.connectionState ==
ConnectionState.waiting) {
return ActivityServices.loadings();
}
return new ListView(
children: snapshot.data.docs
.map((DocumentSnapshot doc) {
Clothes clothes;
clothes = new Clothes(
doc.data()['clothesId'],
doc.data()['clothesName'],
doc.data()['clothesDesc'],
doc.data()['clothesImage'],
doc.data()['clothesCloset'],
doc.data()['clothesAge'],
doc.data()['clothesTag'],
doc.data()['clothesStatus'],
doc.data()['clothesLaundry'],
doc.data()['createdAt'],
doc.data()['updatedAt'],
);
print(doc.data()['clothesName']);
return CardClothesLemari(clothes: clothes);
}).toList(),
);
},
),
and this is my CardClothesLemari
final Clothes clothes;
CardClothesLemari({this.clothes, this.doc});
#override
_CardClothesLemariState createState() => _CardClothesLemariState();
}
class _CardClothesLemariState extends State<CardClothesLemari> {
#override
Widget build(BuildContext context) {
Clothes cloth = widget.clothes;
final Size size = MediaQuery.of(context).size;
if (clothes == null) {
return Container();
} else {
return Padding(
padding:
EdgeInsets.only(top: 5.0, bottom: 5.0, left: 5.0, right: 5.0),
child: InkWell(
onTap: () {
Navigator.pushNamed(context, DetailClothes.routeName,
arguments: cloth);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(14.0),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 3.0,
blurRadius: 5.0)
],
color: Color(0xffA77665),
),
child: Column(children: [
Padding(
padding: EdgeInsets.only(top: size.height * 0.04),
),
Hero(
tag: 'assets/images/dummy.jpg',
child: CircleAvatar(
radius: 55,
backgroundImage: AssetImage("assets/images/dummy.jpg"),
),
),
SizedBox(height: 7.0),
Text(
//show clothes name
cloth.clothes,
style: TextStyle(
fontSize: 14,
fontFamily: GoogleFonts.openSans().fontFamily,
fontWeight: FontWeight.w700,
color: Color(0xffF0E8E1)),
textAlign: TextAlign.center,
),
Padding(
padding: EdgeInsets.only(top: 8),
child:
Container(color: Color(0xFFEBEBEB), height: 2.9657),
),
]))));
}
}
}
this is the screenshot of my firestore
Add listview inside the ConnectionState.done like below code.
if (snapshot.connectionState == ConnectionState.done) {
return new ListView(
children: snapshot.data.docs
.map((DocumentSnapshot doc) {
Clothes clothes;
clothes = new Clothes(
doc.data()['clothesId'],
doc.data()['clothesName'],
doc.data()['clothesDesc'],..........<Rest of the code>......
}
As per your database structure you're entering wrong query. Kindly take a look below code
StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance
.collection('closet')
.doc('your_document_id')
.collection('clothes')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text('Loading...');
} else {
return ListView.builder(
itemCount: snapshot.data.docs.length,
shrinkWrap: true,
itemBuilder: (context, int index) {
QueryDocumentSnapshot<Map<String, dynamic>> data = snapshot.data.docs[index];
return Text(data.data()['clothesName']);
},
);
}
});

using FutureBuilder to get Future<String> from firestore

This is my code in which I want to display an email which is a Future and I will get it from my firestore.However, I am not sure how I will need to retrieve my value using FutureBuilder which I want to use as a string.
This is my method to get my email:
Future<String> getEmail() async {
String _email = (await FirebaseAuth.instance.currentUser()).email;
DocumentSnapshot snapshot = await _firestore.collection('users')
.document(_email)
.collection('met_with')
.document('email')
.get();
// print("data: ${snapshot.data}"); // might be useful to check
return snapshot.data['email']; // or another key, depending on how it's saved
}
this is my updated code:
#override
Widget build(BuildContext context) {
return Card(
elevation: 3.0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
child: ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage(imagePath),
),
trailing: Icon(Icons.more_horiz),
title: Text(
email,
style: TextStyle(
c #override
Widget build(BuildContext context) {
return Card(
elevation: 3.0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
child: ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage(imagePath),
),
trailing: Icon(Icons.more_horiz),
title: Text(
email,
style: TextStyle(
color: Colors.deepPurple[700],
fontWeight: FontWeight.bold,
),
),
subtitle: Text(infection),
onTap: () => showModalBottomSheet(
context: context,
builder: (builder) {
return FutureBuilder(
future: getEmail(),
builder: (BuildContext context, snapshot) {
if(snapshot.hasData){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: CircularProgressIndicator(),
);
}else{
return Padding(padding: EdgeInsets.symmetric(vertical: 50.0, horizontal: 10.0),
child: Column(
children: <Widget>[
BottomSheetText(
question: 'Email', result: snapshot.data['email']),
SizedBox(height: 5.0),
BottomSheetText(
question: 'Contact Time',result:"lol"),// getTimeStamp().toString()),
SizedBox(height: 5.0),
BottomSheetText(
question: 'Contact Location',
result: "help"),
SizedBox(height: 5.0),
BottomSheetText(question: 'Times Contacted', result: "lool",),
],
),
);
}
}else{
return CircularProgressIndicator();}
}
);
}
),
),
);
}
}
Here is my firebase database:
enter image description here
Your query is wrong, try following one.
Future<String> getEmail() async {
String _email = (await FirebaseAuth.instance.currentUser()).email;
var a = await Firestore.instance
.collection("met_with")
.where('email', isEqualTo:. _email )
.getDocuments();
return a.documents[0]['email'];
}
And to call this method you need futureBuilder.
FutureBuilder(
future: getEmail(),
builder: (BuildContext context, snapshot) {
if(snapshot.hasData){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: CircularProgressIndicator(),
);
}else{
return Center( // here only return is missing
child: Text(snapshot.data['email'])
);
}
}else if (snapshot.hasError){
return Text('no data');
}
return CircularProgressIndicator();
},
),
You need to use a FutureBuilder:
FutureBuilder(
future: getEmail(),
builder: (BuildContext context, snapshot) {
if(snapshot.hasData){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: CircularProgressIndicator(),
);
}else{
return Center( // here only return is missing
child: Text(snapshot.data['email'])
);
}
}else if (snapshot.hasError){
Text('no data');
}
return CircularProgressIndicator();
},
),
This way you can use the returned value of the method inside the build method. Also change the Future method to the following:
Future<String> getEmail() async {
String _email = (await FirebaseAuth.instance.currentUser()).email;
return await _firestore.collection('users')
.document(_email)
.collection('met_with')
.document('email')
.get();
}