RangeError when querying for Document in Firebase - firebase

I'm trying to query for data in Firebase with the following method:
static Future<QuerySnapshot> getUserData(String creatorId) {
Future<QuerySnapshot> data = _firestore
.collection('users')
.where('creatorId', isEqualTo: creatorId)
.getDocuments();
return data;
}
I'm then trying to access the data via this FutureBuilder:
body: FutureBuilder(
future: DatabaseService.getUserData(widget.ride.creatorId),
//future: DatabaseService.getUserData(widget.ride.creatorId),
builder: (context, snapshot) {
// if (!snapshot.hasData) {
// }
//User user = User.fromDoc(snapshot.data);
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Color(0xff192C43),
valueColor: AlwaysStoppedAnimation(
Color(0xff213a59),
),
),
);
}
User user = User.fromDoc(snapshot.data.documents[0]);
return SearchCardItemExtended(user: user, ride: widget.ride,);
},
),
There is always only one User with the same creatorId. That is why I am calling the document on [0].
When I tap on the button that calls the FutureBuilder I get the following Exception:
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following RangeError was thrown building FutureBuilder<QuerySnapshot>(dirty, state: _FutureBuilderState<QuerySnapshot>#cff34):
RangeError (index): Invalid value: Valid value range is empty: 0
The relevant error-causing widget was:
FutureBuilder<QuerySnapshot> file:///C:/Users/Paul/AndroidStudioProjects/leaf/leaf/lib/screens/search_card_info.dart:61:13
When the exception was thrown, this was the stack:
#0 List.[] (dart:core-patch/growable_array.dart:149:60)
#1 _SearchCardInfoState.build.<anonymous closure> (package:leaf/screens/search_card_info.dart:80:59)
#2 _FutureBuilderState.build (package:flutter/src/widgets/async.dart)
#3 StatefulElement.build (package:flutter/src/widgets/framework.dart:4334:27)
#4 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4223:15)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
A very similar query and FutureBuilder elsewhere in the Code work.
This is the other FutureBuilder:
body: FutureBuilder(
future: DatabaseService.searchRides(origin, destination, date, time),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Color(0xff192C43),
valueColor: AlwaysStoppedAnimation(
Color(0xff213a59),
),
),
);
}
if (snapshot.data.documents.length == 0) {
return Center(
child: Text(
'Uppss...\n'
'Leider wurden keine passenden Fahrten gefunden.\n'
'Schau doch später noch mal vorbei.',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'UbuntuLight',
fontSize: 14,
color: Color(0xffE6EFE9),
height: 1.6,
),
),
);
}
return ListView.builder(
physics: new BouncingScrollPhysics(),
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
Ride ride = Ride.fromDoc(snapshot.data.documents[index]);
return SearchCardItem(num: index, ride: ride);
},
);
},
),
What could be the problem here?

Jus change your code like this.
if (snapshot.hasData && snapshot.data.length>0) {
User user = User.fromDoc(snapshot.data.documents[0]);
//..Implement what you want here}
You are facing this error because there is no result from firebase then your are trying to call |0]but there is no element at 0. You have to wrap it in a conditinnal way. So it will be executed only when there are more then on user in snapshot.data

Plese check condition snapshot.data.documents.isEmpty or not
if(snapshot.data.documents.length!=0){
User user = User.fromDoc(snapshot.data.documents[0]);
return SearchCardItemExtended(user: user, ride: widget.ride,);
}
return new Container();

Related

How to catch exceptions in Flutter streambuilder's stream

I want to use try{} catch(){} in my StreamBuilder's Stream, because ${globals.currentUid} is initially set as ''(empty string) and makes exception when the program first runs,
but I can't find any way to make try catch in stream.
Below is my streamBuilder
StreamBuilder(
stream: FirebaseFirestore.instance
.collection(
'user/${globals.currentUid}/friends')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return Text(
'Error: ${snapshot.error}',
);
}
final docs = snapshot.data!.docs;
return Text(
docs.length.toString(),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
));
}),
This code makes this error :
_AssertionError ('package:cloud_firestore/src/firestore.dart': Failed assertion: line 63 pos 7: '!collectionPath.contains('//')': a collection path must not contain "//")
What I want to do is this below,
try{
StreamBuilder(
stream: FirebaseFirestore.instance
.collection(
'user/${globals.currentUid}/friends')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return Text(
'Error: ${snapshot.error}',
);
}
final docs = snapshot.data!.docs;
return Text(docs.length.toString(),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
));
})
} on _AssertionError catch(e){
return Text('0',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
));
}
and this is grammatically wrong. Is there any solution for this?
The exception in this case is not actually produced by the stream, but rather by the collection method that is called with an invalid argument. You'll probably want to completely avoid creating the StreamBuilder until globals.currentUid has been initialized with a valid value.
You can do so with a simple if statement or with the ternary conditional operator. For example, assuming your StreamBuilder is child to a Container:
Container(
child: globals.currentUid != '' ?
StreamBuilder( // This will be built only if currentUid is not empty
stream: FirebaseFirestore.instance
.collection(
'user/${globals.currentUid}/friends')
.snapshots(),
builder: (
BuildContext context,
AsyncSnapshot snapshot,
) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
final docs = snapshot.data!.docs;
return Text(
docs.length.toString(),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
);
},
)
: Container(), // An empty container will be shown if currentUid is empty
),

Bad state: field does not exist within the DocumentSnapshotPlatform. Flutter and firebase

I'm trying to build a list from a collection from firebase database but I'm running into a problem with the stream builder snapshots.
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection("users").snapshots().where((event) => true),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data != null) {
return ListView.builder(
itemBuilder: (listContext, index) =>
buildItem(snapshot.data.docs[index]),
itemCount: snapshot.data.docs.length,
);
}
return Container();
},
));
}
buildItem(doc) {
return (userId != doc['id'])
? GestureDetector(
onTap: () {
//Navigator.push(context, MaterialPageRoute(builder: (context) => Page(docs: doc)));
},
child: Card(
color: Colors.black,
child: Container(
height: 60,
child: Center(
child: Text(doc['name'],
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
),
),
)
: Container();
}
Here is the whole error:
======== Exception caught by widgets library =======================================================
The following StateError was thrown building:
Bad state: field does not exist within the DocumentSnapshotPlatform
When the exception was thrown, this was the stack:
#0 DocumentSnapshotPlatform.get._findKeyValueInMap (package:cloud_firestore_platform_interface/src/platform_interface/platform_interface_document_snapshot.dart:86:7)
#1 DocumentSnapshotPlatform.get._findComponent (package:cloud_firestore_platform_interface/src/platform_interface/platform_interface_document_snapshot.dart:104:41)
#2 DocumentSnapshotPlatform.get (package:cloud_firestore_platform_interface/src/platform_interface/platform_interface_document_snapshot.dart:120:26)
#3 _JsonDocumentSnapshot.get (package:cloud_firestore/src/document_snapshot.dart:92:48)
#4 _JsonDocumentSnapshot.[] (package:cloud_firestore/src/document_snapshot.dart:96:40)
...
====================================================================================================
The builder is building the list but its giving a red error section directly below it.
The doc in your buildItem method is a DocumentSnapshot object, which doesn't have an [] defined as far as I know.
I think you're missing a call to data():
userId != doc.data()['id']
If you get another error message after this change, please search for it on Stack Overflow first as I know there have been some recent changes in how types are exposed from a document snapshot.

Firebase Real Time Database triggers `null` error if there is no matching data

In my flutter code, I am trying to get data from the Firebase Real-Time Database. Below is my code.
final DatabaseReference reference = FirebaseDatabase.instance.reference().child('chat_room');
return Scaffold(
body: StreamBuilder(
stream:
reference.orderByChild("email").equalTo("abcd#test.com").onValue,
builder: (context, snapshot) {
if (snapshot == null || !snapshot.hasData) {
return Container(child: Center(child: Text("No data")));
} else {
Map<dynamic, dynamic> map = snapshot.data.snapshot.value;
return ListView.builder(
itemCount: map.values.toList().length,
itemBuilder: (context, index) {
String imageURL = map.values.toList()[index]["imageUrl"];
return Container(
margin: EdgeInsets.only(top: 10),
child: ListTile(
leading: CircleAvatar(
radius: 30.0,
backgroundImage: NetworkImage(imageURL),
backgroundColor: Colors.transparent,
),
title: Text(
map.values.toList()[index]["email"],
),
),
);
});
}
}),
);
Notice, I am loading data where the email is equal to abcd#test.com. The code works great if there are record for abcd#test.com. But if the database is empty or no records for abcd#test.com, I AM getting the below error
The following NoSuchMethodError was thrown building StreamBuilder<Event>(dirty, state: _StreamBuilderBaseState<Event, AsyncSnapshot<Event>>#ad47f):
The getter 'values' was called on null.
Receiver: null
Tried calling: values
The relevant error-causing widget was
StreamBuilder<Event>
package:xxx/…/chat/chat_list_supplier.dart:19
When the exception was thrown, this was the stack
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 _ChatListSupplierState.build.<anonymous closure>
package:xxx/…/chat/chat_list_supplier.dart:28
How can I fix this?
The problem is that there is a snapshot, but the snapshot contains no data. It's easiest to catch this in:
builder: (context, snapshot) {
if (snapshot == null || !snapshot.hasData || snapshot.data.snapshot.value == null) {
return Container(child: Center(child: Text("No data")));
} else {
...

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

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

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