Getting data as null from snapshot.data in Flutter - firebase

I can't find the reason for getting this error cuz there is data stored on firestore and i've also handled possible exceptions. Th StreamBuilder QuerySnapshot Widget is throwing exception. How could i tackle this problem plzz help
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class AdminScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
CollectionReference users = FirebaseFirestore.instance.collection('complaints');
return StreamBuilder<QuerySnapshot>(
stream: users.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return ListView(
children: snapshot.data.docs.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document.data()['Name']),
subtitle: new Text(document.data()['Complaint']),
);
}).toList(),
);
},
);}
}
Error:
A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 370 pos 10: 'data != null'
by StreamBuilder<QuerySnapshot> Widget
Firestore SS:

StreamBuilder will emit null as the first event if no initialData is given. To mitigate, you should first check if the data is null using snapshot.hasData before trying to read it such as:
if(!snapshot.hasData) {
return Center(child: CircularProgressIndicator()));
}
// from here on you can access the data after you have checked it's not null:

Related

Document snapshot with StreamBuilder

I am trying to implement a StreamBuilder for a specific document in a collection, however it is returning the error "null"
class _StatusBarState extends State<StatusBar> {
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseFirestore.instance.collection('notificationsE3').doc('VlELFOHiOjCCQ3wSfpd8').snapshots(),
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot){
if (!snapshot.hasData){
return Text('loading');
}
if (!snapshot.hasError){
print(snapshot.error);
print(snapshot.toString());
return Text('something went wrong');
}
return StatusState(snapshot.data?['status']);
}
);
}
}
I am certain I have the Collection and Document ID correct, why am I getting a null error?
Terminal Output:
null
AsyncSnapshot<DocumentSnapshot<Map<String, dynamic>>>(ConnectionState.active, Instance of '_JsonDocumentSnapshot', null, null)
My QuerySnapshots are working fine in the same project.

Flutter/Firestore/Provider - Error shown for split second then stream displayed, how can I load stream values on startup?

I am using a Stream Provider to access Firestore data and pass it around my app. The problem I am facing starts when I first run the app. Everything starts as normal but as I navigate to the screen where I am using the Stream values in a list view, I initially get an error before the UI rebuilds and the list items appear after a split second. This is the error I get:
════════ Exception caught by widgets library ═══════════════════════════════════
The following NoSuchMethodError was thrown building OurInboxPage(dirty, dependencies: [_InheritedProviderScope<List<InboxItem>>]):
The getter 'length' was called on null.
Receiver: null
Tried calling: length
I'm guessing this has something to do with the load time to access the values and add them to the screen? How can I load all stream values when the app starts up to avoid this?
Here is my Stream code:
Stream<List<InboxItem>> get inboxitems {
return orderCollection
.where("sendTo", isEqualTo: FirebaseAuth.instance.currentUser.email)
.snapshots()
.map(
(QuerySnapshot querySnapshot) => querySnapshot.docs
.map(
(document) => InboxItem.fromFirestore(document),
)
.toList(),
);
}
I then add this to my list of Providers:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MultiProvider(
providers: [
StreamProvider<List<InboxItem>>.value(value: OurDatabase().inboxitems),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<OurUser>(
builder: (_, user, __) {
return MaterialApp(
title: 'My App',
theme: OurTheme().buildTheme(),
home: HomepageNavigator(),
);
},
);
}
}
And finally the page I want to display the stream items:
class OurInboxPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
List<InboxItem> inboxList = Provider.of<List<InboxItem>>(context);
return Scaffold(
body: Center(
child: ListView.builder(
itemCount: inboxList.length,
itemBuilder: (context, index) {
final InboxItem document = inboxList[index];
return Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(document.event),
Icon(Icons.arrow_forward_ios)
],
),
);
},
),
),
);
}
}
Thanks
Yeah its trying to build before the data is populated, hence the null error.
Wrap your ListView.builder in a StreamBuilder and having it show a loading indicator if there's no data.
StreamBuilder<List<InboxItem>>(
stream: // your stream here
builder: (context, snapshot) {
if (snapshot.hasData) {
return // your ListView here
} else {
return CircularProgressIndicator();
}
},
);
I'm assuming your not using the latest version of provider because the latest version requires StreamProvider to set initialData.
If you really want to use StreamProvider and don't want a null value, just set its initialData property.
FROM:
StreamProvider<List<InboxItem>>.value(value: OurDatabase().inboxitems),
TO:
StreamProvider<List<InboxItem>>.value(
value: OurDatabase().inboxitems,
initialData: <InboxItem>[], // <<<<< THIS ONE
),
If you want to display some progress indicator while getter function inboxitems is executed initially. You don't need to modify the StreamProvider, and just add a null checking in your OurInboxPage widget.
class OurInboxPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final List<InboxItem>? inboxList =
Provider.of<List<InboxItem>?>(context, listen: false);
return Scaffold(
body: inboxList == null
? const CircularProgressIndicator()
: ListView.builder(
itemCount: inboxList.length,
itemBuilder: (_, __) => Container(
height: 100,
color: Colors.red,
),
),
);
}
}
There are 2 ways to solve the issue.
Use the progress bar while the data is loading.
StreamBuilder<int>(
stream: getStream(),
builder: (_, snapshot) {
if (snapshot.hasError) {
return Text('${snapshot.error}');
} else if (snapshot.hasData) {
return Text('${snapshot.data}');
}
return Center(child: CircularProgressIndicator()); // <-- Use Progress bar
},
)
Provide dummy data initially.
StreamBuilder<int>(
initialData: 0, // <-- Give dummy data
stream: getStream(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text('${snapshot.error}');
return Text('${snapshot.data}');
},
)
Here, getStream() return Stream<int>.

"NoSuchMethodError: The getter 'docs' was called on null" Error Flutter Firebase

I'm getting the error "NoSuchMethodError: The getter 'docs' was called on null. Receiver: null Tried Calling: docs" whenever I try to use .orderby("POST_ID", descending: true. If someone has an answer to why I'm getting this error and how to fix it please help!
Here is my code:
Container(
margin: EdgeInsets.only(top: 100.0),
child: StreamBuilder(
stream: FirebaseFirestore.instance
.collection("Cities")
.doc(globals.selectedCity)
.collection("Posts")
.orderBy("POST_ID", descending: true)
.where("Category", isEqualTo: globals.selectedCategory)
.snapshots(),
builder: (context, postSnapshot) {
return ListView.builder(
itemCount: postSnapshot.data.docs.length,
itemBuilder: (BuildContext context, int index) {
switch (postSnapshot.data.docs[index]["Type"]) {
case "Image":
return new ImageCard(
imageLink: postSnapshot.data.docs[index]
["ImageLink"],
imageDescription: postSnapshot.data.docs[index]
["ImageDescription"],
posterName: postSnapshot.data.docs[index]
["PosterName"],
);
break;
case "Text":
return new TextCard(
postText: postSnapshot.data.docs[index]
["PostText"],
posterName: postSnapshot.data.docs[index]
["PosterName"],
);
break;
Problem is here:
(postSnapshot.data.docs[index]["Type"])
You have to ensure first that you got the data from firestore. In your case when connection state is connecting or if snapshot has error you invoke docs on null object. Consider building widget tree with checks like this:
class UserInformation extends StatelessWidget {
#override
Widget build(BuildContext context) {
CollectionReference users = FirebaseFirestore.instance.collection('users');
return StreamBuilder<QuerySnapshot>(
stream: users.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return new ListView(
children: snapshot.data.docs.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document.data()['full_name']),
subtitle: new Text(document.data()['company']),
);
}).toList(),
);
},
);
}
}

Use Cloud Firestore on Flutter. But I got exception by widget Library

When I read a data from the Cloud Firestore.
I could get the data, but I caught the below exception.
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building StreamBuilder(dirty, state: _StreamBuilderBaseState<QuerySnapshot, AsyncSnapshot>#4f115):
The getter 'docs' was called on null.
Receiver: null
Tried calling: docs
I tried some idea on stackoverflow but I couldn't resolve.
Here is my code.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class AdminHome extends StatefulWidget {
final String email;
AdminHome({#required this.email});
#override
State<StatefulWidget> createState() {
return _AdminHomeState(this.email);
}
}
class _AdminHomeState extends State<AdminHome> {
final fireStoreInstance = FirebaseFirestore.instance;
String email;
_AdminHomeState(this.email);
#override
Widget build(BuildContext context) {
print("This email is $email");
return Scaffold(
appBar: AppBar(
title: Text("Admin Home Window"),
),
body: StreamBuilder<QuerySnapshot>(
stream: fireStoreInstance.collection(email).snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
return ListView(
children: snapshot.data.docs.map((DocumentSnapshot document) {
if (snapshot.data != null && !snapshot.hasError) {
return Card(
child: ListTile(
title: Text(document.data()["gameName"]),
onTap: () {
print("tapped");
Navigator.pushNamed(context, '/adminGameDetail');
},
),
);
} else if (snapshot.data == null && !snapshot.hasError) {
return Center(child: Text('No data'));
} else {
return Center(
child: Text('Woooops'),
);
}
}).toList(),
);
},
),
);
}
}
Please help it.
snapshot.data is not yet loaded while you are trying to access it. Try this:
StreamBuilder<QuerySnapshot>(
stream: fireStoreInstance.collection(email).snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if(!snapshot.hasData) return Text("Still Loading"); // return whatever widget you want to show while the data is being loaded.
if(snapshot.hasError) return Text("Error"); // Return whatever widget you want to show when an error occurs.
return ListView(
children: snapshot.data.docs.map((DocumentSnapshot document) {
if (snapshot.data != null && !snapshot.hasError) {
return Card(
child: ListTile(
title: Text(document.data()["gameName"]),
...
...
... Rest of the code

I keep getting a NoSuchMethodError call in my Flutter application regarding Firestore

I'm stuck on this problem. I have been trying to render items from my Firestore collection. Everytime I try to retrieve it, I keep getting this error:
"Closure call with mismatched arguments: function '[]'
Receiver: Closure: () => Map<String, dynamic> from Function 'data':.
Tried calling: []("title")
Found: []() => Map<String, dynamic>"
I have tried to look online for solutions but I feel a bit stuck on what I am supposed to do. I have commented the part that is causing an error in the ListTile. This is something I have been stuck on in the past few days. I have all the dependencies installed such as the Firestore one so I don't think it is a dependency issue. Although I would greatly appreciate anyone who is able to help me by any chance.
import 'package:flutter/material.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:tanbo_mobile/errorpage.dart';
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
class HomeTab extends StatefulWidget {
#override
_HomeTabState createState() => _HomeTabState();
}
class _HomeTabState extends State<HomeTab> {
Future getPosts() async {
var firestoreReference = FirebaseFirestore.instance;
QuerySnapshot qn = await firestoreReference.collection('posts').get();
return qn.docs;
}
#override
Widget build(BuildContext context) {
return Container(
child:
FutureBuilder(
future: getPosts(),
builder: (_, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
// The length of our data we will return
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
return ListTile(
// This line is causing the errors!
title: Text(snapshot.data[index].data['text']),
);
}
);
}
return Center(
child: CircularProgressIndicator(),
);
},
),
);
}
}
Image of error in application
Firestore data structure
DocumentSnapshot.data() is a method not a getter, therefore it's necessary to include the parentheses to actually call the method and obtain the returned Map. This is why dart is confused and throws an error as you're trying to use the [] operator on a function reference.
Replace the line that is giving you errors with the following:
title: Text(snapshot.data[index].data()['text']),

Resources