I'm using Firestore and I tried to get streams by Streambuilder.
However, This error happened.
The following NoSuchMethodError was thrown building StreamBuilder<DocumentSnapshot<Object>>
(dirty, state: _StreamBuilderBaseState<DocumentSnapshot<Object>,
AsyncSnapshot<DocumentSnapshot<Object>>>#32fdb):
The method 'data' was called on null.
Receiver: null
Tried calling: data()
And this is my code.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class UserDetailPage extends StatefulWidget {
String uid;
UserDetailPage(this.uid);
#override
_UserDetailPageState createState() => _UserDetailPageState();
}
class _UserDetailPageState extends State<UserDetailPage> {
final List<String> datas = <String>['a', 'b', 'c', 'd', 'e', 'f', 'g', '1', '2','3', '4', '5', '6'];
CollectionReference userstream = FirebaseFirestore.instance.collection('users');
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('User Detail'),
),
body:_buildBody(),
);
}
_buildBody() {
return StreamBuilder(
stream: userstream.doc(widget.uid).snapshots(),
builder: (context, snapshot){
Map<String, dynamic> user_data =snapshot.data.data();
if(snapshot.hasError){
return Text('ERROR');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return Padding(
padding: const EdgeInsets.all(20.0),
child: ListView.separated(
padding: EdgeInsets.only(left: 20, right: 20),
itemCount: 13,
separatorBuilder: (BuildContext context, int index) => const Divider(),
itemBuilder: (BuildContext context, int index){
return Center(
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(datas[index]),
Text(user_data[datas[index]] is int?user_data[datas[index]].toString():user_data[datas[index]])
],
),
),
);
}
)
);
},
);
}
}
Interesting thing is that Immediately after this error occurs, the result I wanted appears on the app.
So I thought the problem occurs in initstate() but I dont know exactly what is wrong.
By the way, this Page is called from
UserDetailPage( doc.get('uid')!=null?doc.get('uid'):'5AJUsH5LYaQcBiTtO5MA7d6OKx72');
The AsyncSnapshot wraps data that is loaded asynchronously. Calling snapshot.data without checking whether the data is available (as you do in the code below), means you are ignoring this fact and might as well not use a StreamBuilder:
stream: userstream.doc(widget.uid).snapshots(),
builder: (context, snapshot){
Map<String, dynamic> user_data =snapshot.data.data();
The proper way to deal with the stream is shown in the FlutterFire documentation on realtime listeners. The required change for you is that you only call snapshot.data after all the checks, instead of before them:
builder: (context, snapshot){
if(snapshot.hasError){
return Text('ERROR');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
Map<String, dynamic> user_data =snapshot.data.data();
Related
I have problem with this code,
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({ Key? key }) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference users = FirebaseFirestore.instance.collection('users');
Stream<QuerySnapshot<Map<String, dynamic>>> collectionStream = FirebaseFirestore.instance.collection('users').snapshots();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home Page'),
),
body: StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: collectionStream,
builder: (context, snapshot) {
return Container(
child: ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data!.docs[index].data()['name']),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
users.doc(snapshot.data!.docs[index].id).delete();
},
),
);
}
),
);
},
),
);
}
}
This line that makes this program error, operator (!):
snapshot.data!.docs.length
snapshot.data!.docs[index].data()['name']
snapshot.data!.docs[index].id
initially this code does not error, but when I rerun it appears : Exception has occurred. _CastError (Null check operator used on a null value). I've tried to fix it but still failed. Is there a way to solve this problem ?
This error means that the snapshot.data is null.
And you're using the null-check operator on it in the line snapshot.data!.
Solution:
You need to check if the data is null and display something like a loading screen while the app waits for snapshot.data to have a value like this:
body: StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: collectionStream,
builder: (context, snapshot) {
if (snapshot.data == null) {
return Center(child: CircularProgressIndicator());
}
return Container(
child: ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data.docs[index].data()['name']),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
users.doc(snapshot.data.docs[index].id).delete();
},
),
);
},
),
);
}
)
And since you're checking if snapshot.data is null, you can remove the null-check operator from its usage.
So snapshot.data! in snapshot.data!.docs.length becomes snapshot.data like snapshot.data.docs.length.
I'm having trouble reading data from firestore. I want to display a user's name on screen after it is stored in firestore.
firestore document
my code is as follows, and thank you in advance for any assistance given:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
final db = FirebaseFirestore.instance.collection('users').snapshots();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: StreamBuilder<QuerySnapshot>(
stream: db,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
} else
return ListView(
children: snapshot.data!.docs.map((doc) {
return Card(
child: ListTile(
title:
// Text(doc.data()['title']),
Text(doc.get('First name')
),
));
}).toList(),
);
},
),
final Stream<DocumentSnapshot<Map<String, dynamic>>> db = FirebaseFirestore.instance
.collection('users')
.doc('Personal details')
.snapshots();
...
body: StreamBuilder<DocumentSnapshot>(
stream: db,
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) return Text('Something went wrong');
if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
dynamic data = snapshot.data.data();
print(data);
print(data['First name']); // should print 'Guy'
print(data['Last name']); // should print 'Fang'
return Text(data['First name']);
},
),
In the code you showed, you are listening to the 'users' collection, instead, listen to the document 'Personal details' as shown above.
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 have app that I want to retreive data which are messages represented in uid document from Firestore database as explained here and these messages stored like so :
ChatRoom->chatRoomId->chat-> uid-> messages
but I receive this error :
The following NoSuchMethodError was thrown building StreamBuilder(dirty, state: _StreamBuilderBaseState<dynamic,
AsyncSnapshot>#56cb5): Class 'QuerySnapshot' has no instance
getter 'document'. Receiver: Instance of 'QuerySnapshot' Tried
calling: document
The relevant error-causing widget was: StreamBuilder
file:///Users/ahmedhussain/Downloads/khamsat/Client%20Apps/HPX-KSA/hpx_ksa/lib/Screens/messages.dart:21:12
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 _MessagesState.chatRoomList. (package:hpxksa/Screens/messages.dart:25:38)
Here is my code:
class _MessagesState extends State<Messages> {
Stream chatRoomsStream;
Widget chatRoomList(){
return StreamBuilder(
stream: chatRoomsStream,
builder: (context, snapshot){
return snapshot.hasData ? ListView.builder(
itemCount: snapshot.data.document.length,
itemBuilder: (context, index){
return ChatRoomTile(
username: snapshot.data.documents[index].data["chatRoomId"]
.toString().replaceAll("_", "").replaceAll(Constants.myName, "replace"),
chatRoomId:snapshot.data.documents[index].data["chatRoomId"]
);
}) : Container();
}
);
}
getUserInfogetChats() {
DatabaseService().getChatRooms(Constants.myName).then((value) {
setState(() {
chatRoomsStream = value;
});
});
}
#override
void initState() {
getUserInfogetChats();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: chatRoomList(),
);
}
}
class ChatRoomTile extends StatelessWidget {
final String username;
final String chatRoomId;
ChatRoomTile({this.username, this.chatRoomId});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>Conversation(chatRoomId: chatRoomId,)));
},
child: Container(
color: Colors.black26,
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: <Widget>[
Container(
height: 40,
width: 40,
alignment: Alignment.center,
decoration: BoxDecoration(
color: kPrimaryColor,
borderRadius: BorderRadius.circular(40),
),
child: Text("${username.substring(0,1).toUpperCase()}"),
),
SizedBox(width: 8,),
Text(username),
],
),
),
);
}
}
Here is my get function to retreive chats that contains user name:
getChatRooms(String username)async{
return await Firestore.instance.collection("ChatRoom").
where("users", arrayContains: username).
snapshots();
}
The error that you received is quite clear about what the issue is. QuerySnapshot doesn't have a document property. You likely intended to use the documents property, which is more consistent with your attempt to use a ListView.
Changing instances of snapshot.data.document to snapshot.data.documents will solve this particular issue.
return StreamBuilder(
stream: chatRoomStream,
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
return ChatRoomTile(
**snapshot.data.docs[index].data()['chatRoomId']**);
},
)
: Container();
},
);
So here I am trying to fetch the data from firebase by using DocumentSnapshot.
I want to print the value of document['display_name']
Collection = user_data
document = 3vIf92LIJQ7pu7MpUwH1
display_name = element of document.
Output: 'Error has Occured' on screen
class _HomeViewState extends State<HomeView> {
Future<DocumentSnapshot> getDocument() async {
return Firestore.instance
.collection('user_data')
.document('3vIf92LIJQ7pu7MpUwH1')
.get();
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: FutureBuilder(
future: getDocument(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) return Text('Error has occured');
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
if (snapshot.hasData) {
return Column(
children: <Widget>[
Text(snapshot.data['display_name']),
],
);
}
You probably have an error because of your firestore security rules. Also, you will need to access snapshot.data.data['display_name'] instread of snapshot.data['display_name'] to get the value from firestore.
if (snapshot.hasData) {
return Column(
children: <Widget>[
Text(snapshot.data.data['display_name']),
],
);
}
If hasError is true, you'll want to print snapshot.error to see what the actual problem is:
if (snapshot.hasError) return Text('Error has occurred: ${snapshot.error}');