Flutter/ Firestore : Class 'QuerySnapshot' has no instance getter 'document' - firebase

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();
},
);

Related

Exception has occurred. _CastError (Null check operator used on a null value)

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.

flutter : not able to display image from firebase firestore

I am trying to get array of images to be displayed on container widget which is stored in firebase firestore. The url is stored with index in firestore and cloud storage. Here is the complete code below. I followed the code provided online, I am not sure what I am missing or where I went wrong. pls help me out.Thanks in advance.
class NewImage extends StatefulWidget{
List<String> urls;
int currentIndex;
VoidCallback onImageTap;
NewImage({Key key,#required this.urls,#required this.currentIndex,#required this.onImageTap})
:super(key:key);
#override
_NewImage createState() => _NewImage();
}
class _NewImage extends State<NewImage>
with SingleTickerProviderStateMixin{
List<String> images = [];
final auth = FirebaseAuth.instance;
final FirebaseFirestore fb = FirebaseFirestore.instance;
#override
void initState() {
super.initState();
getImages();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SafeArea(
child: Column(
children: [
Container(
height: 160.0,
padding: EdgeInsets.symmetric(vertical: 15.0,horizontal: 15.0),
child: FutureBuilder(
future: getImages(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: snapshot.data.docs.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
contentPadding: EdgeInsets.all(8.0),
leading: Image.network(
snapshot.data.docs[index].data()["images"],
fit: BoxFit.fill),
);
});
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return CircularProgressIndicator();
},
),
),
],
),
),
),
);
}
Future<QuerySnapshot> getImages() async {
return FirebaseFirestore.instance.collection("users").doc(
auth.currentUser.uid).collection("images").get();
}
}
you are passing array to networkImage instead of image
change it like this
Image.network(
snapshot.data.docs[index].data()["images"][index],// [index] added
fit: BoxFit.fill),

Why is Firestore data giving Class 'QueryDocumentSnapshot' has no instance method '[]'. error?

I am trying to get the image from firestore and it give this error,
the key to the image in database is 'image 1 Url'
the same Code and same structure works on my other app but this one it throws this error
Class 'QueryDocumentSnapshot' has no instance method '[]'.
Receiver: Instance of 'QueryDocumentSnapshot'
Tried calling: []("image 1 Url")
this is the firestore database structure,
class Toyota extends StatefulWidget {
#override
_ToyotaState createState() => _ToyotaState();
}
class _ToyotaState extends State<Toyota> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('toyota').snapshots(),
builder: (context, snapshot) {
if (snapshot.data == null)
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.red,
valueColor: new AlwaysStoppedAnimation<Color>(Colors.teal),
),
);
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) => SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3)),
child: Image.network(
snapshot.data.documents[index]['image 1 Url'],
),
),
),
));
},
));
}
}
the solution I found to use get('String') this work with me
snapshot.data.documents[index].get('image 1 Url')
you can check this for more : https://developers.google.com/android/reference/com/google/firebase/firestore/QueryDocumentSnapshot

Flutter/Firebase - Error in fetching currently logged in user data

I want to fetch currently logged in user data. There is a field in fire_store 'useremail'. When a user logs in, I get his ID and using 'where class' I fetch the animal's data against his ID shown below:
Widget _buildBody(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('booking_tbl').where("useremail", isEqualTo: _firebaseUser.email.toString()).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return _buildList(context, snapshot.data.documents);
},
);
}
Although it is working but it shows error on as well. I need some help to fix this issue or an alternate suggestion for this (Any suggestion or kind help would be highly appreciated):
════════ Exception caught by widgets library
══════════════════════
NoSuchMethodError was thrown building UserBookingHistoryModel(dirty,
state: _UserBookingHistoryModelState#2d8c2):
The getter 'email' was called on null.
Receiver: null
Tried calling: email
Probably the problem is caused by this snippet in Firebase Auth:
void initState() {
super.initState();
widget.auth.getCurrentUser().then((firebaseUserId) {
setState(() {
authStatus = firebaseUserId == null
? AuthStatus.notSignedIn
: AuthStatus.signedIn;
});
});
}
The full code of bookings.dart is here:
class _UserBookingHistoryModelState extends State<UserBookingHistoryModel> {
FirebaseAuth _auth;
FirebaseUser _firebaseUser;
#override
void initState() {
super.initState();
_auth = FirebaseAuth.instance;
_getCurrentUser();
}
_getCurrentUser () async {
_firebaseUser = await FirebaseAuth.instance.currentUser();
setState(() {
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _buildBody(context),
);
}
Widget _buildBody(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('booking_tbl').where("useremail", isEqualTo: _firebaseUser.email.toString()).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return _buildList(context, snapshot.data.documents);
},
);
}
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return ListView(
padding: const EdgeInsets.only(top: 5.0),
children: snapshot.map((data) => _buildListItem(context, data)).toList(),
);
}
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
return Padding(
key: ValueKey(record.animal),
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
),
child: new ListTile(
title: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Text(
"${record.animal} Slaughtering",
style: new TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
),
],
),
)
),
);
}
}
class Record {
final String animal;
final String user;
final DocumentReference reference;
Record.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['animal'] != null),
assert(map['user'] != null),
animal = map['animal'],
user = map['user'];
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
#override
String toString() => "Record<$animal:$user>]";
}
You need to do the following:
Stream<QuerySnapshot> getData() async*{
FirebaseUser firebaseUser = await FirebaseAuth.instance.currentUser();
yield* Firestore.instance.collection('booking_tbl').where("useremail", isEqualTo: firebaseUser.email.toString()).snapshots();
}
Then inside the StreamBuilder use getData():
return StreamBuilder<QuerySnapshot>(
stream: getData(),
builder: (context, snapshot) {
//....
The getData() method is asynchronous, since you are using a StreamBuilder then you need to return a Stream therefore you use the async* keyword, and you emit the result using yield*

Gridview.builder with Firebase realtime database and futurebuilder

Coming from Firestore, I am a little bit struggling how to receive data from Firebase real time database. I just want a nice grid view of images which are loaded from the realtime database.
Error: flutter: The following NoSuchMethodError was thrown building:
flutter: Class 'DataSnapshot' has no instance method '[]'.
flutter: Receiver: Instance of 'DataSnapshot'
I guess it's index related. No idea how to correctly map it within a list.
import 'package:cached_network_image/cached_network_image.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(16.0),
child: new FutureBuilder(
future: FirebaseDatabase.instance
.reference()
.child('messages')
.child('1551276762582')
.orderByChild('messagetype')
.equalTo('1')
.once(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
if (snapshot.data != null) {
return new Column(
children: <Widget>[
new Expanded(
child: new GridView.builder(
// itemCount: item.length,
gridDelegate:
new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2),
itemBuilder: (context, index) {
return GridTile(
child: CachedNetworkImage(
imageUrl: snapshot.data[index]['imageUrl']
.toString()));
},
),
)
],
);
} else {
return new CircularProgressIndicator();
}
} else {
return new CircularProgressIndicator();
}
}));
}
}
I could solve it with the following code. Again, I have to say that the Firebase documentation really lacks, which is quite disappointing, since Firebase is a great tool. Moreover, I do not understand, that there is no documentation on 'How to use Firebase with Flutter' (we are talking about both Google products.) Notwithstanding, here is the working code for anyone, who likes to use Streambuilder with Gridview.builder with the Realtime Database in Flutter:
StreamBuilder(
stream: FirebaseDatabase.instance
.reference()
.child('messages')
.child(groupId)
.orderByChild('messagetype')
.equalTo(1)
.onValue,
builder: (BuildContext context, AsyncSnapshot<Event> snapshot) {
if (snapshot.hasData) {
if (snapshot.data.snapshot.value != null) {
Map<dynamic, dynamic> map = snapshot.data.snapshot.value;
List<dynamic> list = map.values.toList()
..sort(
(a, b) => b['timestamp'].compareTo(a['timestamp']));
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
itemCount: list.length,
padding: EdgeInsets.all(2.0),
itemBuilder: (BuildContext context, int index) {
return Container(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondScreen(
imageUrl: list[index]["imageUrl"])),
);
},
child: CachedNetworkImage(
imageUrl: list[index]["imageUrl"],
fit: BoxFit.cover,
),
),
padding: EdgeInsets.all(2.0),
);
},
);
} else {
return Container(
child: Center(
child: Text(
'Es wurden noch keine Fotos im Chat gepostet.',
style: TextStyle(fontSize: 20.0, color: Colors.grey),
textAlign: TextAlign.center,
)));
}
} else {
return CircularProgressIndicator();
}
})),
Something that I do that helps me solve issues, is by explicitly turning snapshots into Maps the following way.
Map yourModel = Map.from(datasnapshot);
also many times when handling null data or so on I have to turn the asyncSnap value that comes from the future Builder into a Datasnapshot from firebase in the following way
Datasnapshot snap = asyncSnap.data;
then handle for snap being null
if(snap.value!=null){}
Hope this helps! if you need help send me a message

Resources