so i'm creating a todo list app, and it was working fine and all until i upgraded all the packages in my pubspec.yaml, which led to some nasty errors i found a way to fix it but that was when i started experiencing a problem, when i write tasks to my firestore database it doesn't add, and my stream builder doesn't see it but if i add the task manually, my stream builder still wont see it, i need help
how i solved my error in my pubspec
dependency_overrides:
firebase_messaging_platform_interface: 3.1.6
firebase_crashlytics_platform_interface: 3.1.13
cloud_firestore_platform_interface: 5.4.13
firebase_auth_platform_interface: 6.1.11
firebase_storage_platform_interface: 4.0.14
cloud_functions_platform_interface: 5.0.21
firebase_analytics_platform_interface: 3.0.5
firebase_remote_config_platform_interface: 1.0.5
firebase_dynamic_links_platform_interface: 0.2.0+5
firebase_performance_platform_interface: 0.1.0+5
firebase_app_installations_platform_interface: 0.1.0+6
how i add tasks to firebase
FirebaseFirestore.instance.collection('tasks').add(
{
'name': textcontrol,
'description': descriptionControl,
'completed': false,
'DOC': newDate,
'created': DateTime.now(),
'time': newTime.format(context).toString(),
},
);
my stream builder
StreamBuilder<QuerySnapshot>(
builder: (context, snapshot) {
if (!snapshot.hasData)
return Container(
height: constraints.maxHeight * 0.7,
child: Center(
child: Text('press the + icon to add a task'),
),
);
return Expanded(child: _buildList(snapshot.data));
},
stream: FirebaseFirestore.instance
.collection('tasks')
.where('completed', isEqualTo: false)
.snapshots(),
),
When you upload something on the firebase database you have to create a doc within the collection with a unique id and then set your Map, so your code must look like this:
FirebaseFirestore.instance.collection('tasks').doc(doc_name_you_want).set(
{
'name': textcontrol,
'description': descriptionControl,
'completed': false,
'DOC': newDate,
'created': DateTime.now(),
'time': newTime.format(context).toString(),
},
);
Related
I'm trying to retrieve from my collection "Courses" 2 field.
Course code and Course name. My issue when retrieving is that I only managed to retrieve the first field.
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.separated(
itemCount: snapshot.data!.docs.length,
separatorBuilder: (BuildContext context, int index) =>
Divider(height: 1),
// ignore: dead_code
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return ListTile(
contentPadding:
EdgeInsets.symmetric(horizontal: 30, vertical: 10),
selectedTileColor: Color(0xffE5E5E5),
title: Text.rich(
TextSpan(
text: doc["Course code"],
children: <TextSpan>[
TextSpan(text: ":"),
TextSpan(text: doc["Course name"]),
and it shows me this error:
Exception has occurred.
StateError (Bad state: field does not exist within the DocumentSnapshotPlatform)
this is my firebase
I only can retrieve course code I don't know why.
It seems like you have a problem with how Flutter and Firebase interacts with each other. I would like to suggest to check the following threadand especially the comment posted by jschnip which could solve your problem
This is probably related to recent changes in DocumentSnapshot, your
factory is looking for the data map, which used to be in doc, but nows
its in doc.data() - except DocumentID
So for your factory, one way to change it would be to adjust to:
Userr( id: doc.id, email: docdata['email'], username:
docdata['username'], url: docdata['url'], profileName:
docdata['profileName'], bio: docdata['bio'], subject1:
docdata['subject1'], subject2: docdata['subject2']
and when you call
it, you'll need to do something like:
doc.data();
newUserrr = Userr.fromDocument(doc, _docdata);
Hello everybody first of all I'm sorry for my English if its not clear, I'm working on a personal project. so, I'm using StreamBuilder on firestore document with the userID of the user from 'Users' Collections. So, I have retrieved the "imageUrl" field and display it in Image Network in my application, so, I have 'Delete Account' Button, this button will delete the account from firebase auth and also delete the document that the streambuilder listens to it.
So, the error happens because the streambuilder will build ImageNetwork and retrieve the URL from the document field.
Any ideas to handle the error?
this is the code for the streamBuilder that will return NetworkImage
StreamBuilder<DocumentSnapshot>(
stream: Firestore.instance
.collection('Users')
.document(user.getID())
.snapshots(),
builder:
(context, AsyncSnapshot<DocumentSnapshot> snapshot) {
print(snapshot.connectionState);
var userDocument = snapshot.data;
if (userDocument.data.length == 0) {
return const Center(
child: Text(
"Not Available",
style:
TextStyle(fontSize: 30.0, color: Colors.grey),
),
);
} else
return AvatarGlow(
glowColor: Colors.redAccent,
endRadius: 90,
child: Material(
elevation: 8.0,
shape: CircleBorder(),
child: CircleAvatar(
backgroundColor: Colors.grey[100],
child: ClipOval(
child: FadeInImage(
image: NetworkImage(
userDocument['imageUrl'] ??
'https://picsum.photos/250?image=9'),
placeholder: AssetImage('assets/noImage.png'),
),
),
radius: 70,
),
),
);
},
),
Debug error
The getter 'length' was called on null.
Receiver: null
Tried calling: length
The relevant error-causing widget was
StreamBuilder<DocumentSnapshot>
The solution was on if else blocks
StreamBuilder<DocumentSnapshot>(
stream: Firestore.instance
.collection('Users')
.document(user.getID())
.snapshots(),
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.data != null && snapshot.data.exists) {
var userDocument = snapshot.data;
// return something
}
}
For a non-existing document userDocument.data will return null, so userDocument.data.length throws the error you get.
My guess is you want to check if the document exists, which you'd do with:
if (userDocument.exists) {
Also see the reference documentation on DocumentSnapshot class, which is the type of object your userDocument is.
Ok. So, how these StreamBuilder(s) and FutureBuilder(s) are supposed be used are as follows:
Note: the following code should be inside your Builder function.
if(snapshot.hasData){
// Your normal functioning of the app will follow here.
// Now that you know that your snapshot contains data,
// then you access the data.
var userDocument = snapshot.data;
// Now, you can check if the userDocument exists or not.
}
else if(snapshot.hasError){
// return an error message or do something else.
}
// return any default Widget while the data is being loaded.
return CircularProgressIndicator();
Also, I would recommend that once the user requests to delete his/her account, you should navigate back to the home screen...
What I really want to do is take all the ORDER IDs ("order_id") that are in the "deliver" collection and use these IDs in another call, that is, enter in "orders" collection and inform all IDs I got in the "deliver" collection as documents.
my stream:
function() {
Firestore.instance
.collection("delivers")
.document("fvRpb1xDOKejJ5AEqXEeThaqhci1")
.collection("orders")
.snapshots()
.listen((orders) {
orders.documents.forEach((f) {
print("+++++ First +++++ ${f.data}");
Firestore.instance
.collection("orders")
.document(f.documentID)
.snapshots();
});
});
}
My StreamBuilder Bellow:
body: Container(
child: StreamBuilder<QuerySnapshot>(
stream: function(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
print("SNAPSHOT DATA ++++++ ${snapshot.toString()} ++++++}");
// if (snapshot.hasError)
// print("ERRO EM ++++++ ${snapshot.error.toString()} ++++++}");
if (!snapshot.hasData)
return Center(
child: RaisedButton(
onPressed: function, child: Text("press")));
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return circularProgress();
break;
default:
print(
"CONNECTION DEFAULT ++++++ ${snapshot.toString()} ++++++}");
return ListView(
children: snapshot.data.documents
.map((DocumentSnapshot myOrder) {
return Text(myOrder["quantity"]);
}).toList());
}
}),
),
RETURNS:
I/flutter ( 600): +++++ First +++++ {order_id: 2tC5gbAYLoj375w9HrKc}
Performing hot reload... ⡿I/flutter ( 600): SNAPSHOT DATA ++++++ AsyncSnapshot(ConnectionState.none, null, null) ++++++}
my firestore screen shots
https://drive.google.com/drive/u/0/folders/1ZeXog80wvnR-6cTG2VCE0jOVfrSEyDaM
You are not returning anything from function().
Add return keyword before snapshots as :
return Firestore.instance
.collection("delivers")
.document("fvRpb1xDOKejJ5AEqXEeThaqhci1")
.collection("orders")
.snapshots();
or simply put the snapshot in front of the stream, as :
stream:Firestore.instance.collection('delivers').document('fvRpb1xDOKejJ5AEqXEeThaqhci1')____________.snapshots(),
I share a possible cause of problem of: "ALWAYS having null on snapshots results even the data is there in Firebase"
It might be your cloud_firestore version in pubspec.yaml caused the problem. I tried different methods of fetching data on Youtube, but none of them worked, I finally changed the version of cloud_firestore from ^0.14.4 to ^0.13.5, and the data suddenly all appeared! Here is my specific version changes in pubspec.yaml: the commented are the new version that does not work.
# cloud_firestore: ^0.14.4
cloud_firestore: ^0.13.5
firebase: ^7.3.3
# firebase_auth: ^0.18.4+1
firebase_auth: ^0.15.4
# firebase_core: ^0.5.3
firebase_core: ^0.4.4
This might not be the cause of your problem, but it may help some others :D
I'm trying to create chat demo app with firebase in flutter but when i send message, then those message documents are being created at randomly any places in firestore database. thats why my chat screen messages are in wrong manner, means not arranged according to time.
Some piece of code:
method for saving message details to firestore:
Future<void> sendMesssage() async{
if(messagesController.text.length>0){
String msgId = firestore.collection("messages").document().documentID.toString();
await firestore.collection("messages").document(msgId).setData({
'text': messagesController.text,
"from": widget.user.user.email, //sender email Id
"to":widget.chatMateEmail, // receiver email id
"msgId":msgId,
"senderUid": widget.user.user.uid, //sender uid
"receiverUid":widget.receiverUid //receiver uid
});
messagesController.clear();
}
}
UI For chat screen:
method for fetching messages from firestore:
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: firestore.collection("messages").snapshots(),
builder: (context, snapshot){
if(snapshot.hasError){
return Center(child: Text("${snapshot.error}"),);
}
if(!snapshot.hasData){
return Center(child: CircularProgressIndicator(),);
}else{
List<DocumentSnapshot> docs = snapshot.data.documents;
return
Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: docs.length,
itemBuilder: (context, index){
print("Messagessssssss:${docs[index]['text']}");
return Message( // custom class
from: docs[index]['from'],
text: docs[index]['text'],
me: widget.user.user.email == docs[index]['from'],
);
},
),
);
}
},
),
),
chat Screen:
My Cloud Firestore Screenshot:
It got solved according to #DougStevenson sir's answer, I added new field with name "messageTime" and add DateTime.now(), And fetched messages according to messageTime (sort by ascending order ).
I modified a little bit my code & working perfectly:
Future<void> sendMesssage() async{
if(messagesController.text.length>0){
String msgId = firestore.collection("messages").document().documentID.toString();
await firestore.collection("messages").document(msgId).setData({
..........
"messageTime": DateTime.now() // message DateTime
});
messagesController.clear();
}
}
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: firestore.collection("messages").orderBy('messageTime', descending: false).snapshots(), //and sort by ascending order according to datetime.
builder: (context, snapshot){
......
},
),
),
The last few days I spend a lot of time to read through several SO-questions and tutorials. What I'm trying to achieve is, that a user of my flutter app can choose a firebase project and log in with email/password. After the login, obviously, the correct data of the corresponding database should be shown. And that is where I fail.
After a while of reading some sites and questions from SO, I went with the following site to get the first part of the login.
https://firebase.googleblog.com/2016/12/working-with-multiple-firebase-projects-in-an-android-app.html
After working through this article, I was able to successfully log in to my defined firebase projects.
How did I know that the login was successful? I compared the user-uids from the projects with the print statement from my app in the console. That was the prove my configuration for the non-default project is correct.
But now the main problem which I can't solve.
After the login, the data is always of the default firebase project from the google-service.json.
For state management, I choose the provider package, as they mentioned in the I/O '19. So inside my main.dart, I wrap the whole application with MultipleProvider:
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<LoginModel>(
builder: (_) => LoginModel(),
),
ChangeNotifierProvider<Auth>(
builder: (_) => Auth(),
),
],
child: MaterialApp(
title: 'Breaking News Tool',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: RootPage(),
),
);
}
The provided Auth class is a service that connects to firebase sdk and also configure non-default apps to create the needed firebase auth
abstract class BaseAuth {
getDefaultAuth();
getAbnAuth();
...
}
class Auth with ChangeNotifier implements BaseAuth {
...
Auth() {
_configureAbnApp();
_configureProdApp();
}
getDefaultAuth() {
_firebaseAuth = FirebaseAuth.instance;
}
getAbnAuth() {
_firebaseAuth = FirebaseAuth.fromApp(_abnApp);
}
_configureAbnApp() {
FirebaseOptions abnOptions = FirebaseOptions(
databaseURL: 'https://[project-id].firebaseio.com',
apiKey: 'AIzaSxxxxxxxxxxxxxxxx,
googleAppID: '1:10591xxxxxxxxxxxxxxxxxxx');
FirebaseApp.configure(name: 'abn_database', options: abnOptions)
.then((result) {
_abnApp = result;
});
}
...
}
After a log in the app redirects the user to the home_page (StatefulWidget). Here I use a snapshot of the database to show data.
_stream = Firestore.instance.collection(collection).snapshots();
...
Center(
child: Container(
padding: const EdgeInsets.all(10.0),
child: StreamBuilder<QuerySnapshot>(
stream: _stream,
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading...');
default:
return ListView(
children: snapshot.data.documents
.map((DocumentSnapshot document) {
return CustomCard(
docID: document.documentID,
title: document[title],
message: document[message],
fromDate: document[fromDate],
endDate: document[endDate],
disableApp: document[disableApp],
);
}).toList(),
);
}
},
),
),
),
In the beginning, I only had one project to connect to and the data was correct. But now I successfully connect to another project with the correct user-uid, but the data is always from the default project which is defined by the google-service.json.
And at this point, I have no clue why this happens.
Did anyone have an advice or idea?
You create your _stream based on Firestore.instance, which will give you the default firebase app, as documented in the docs:
/// Gets the instance of Firestore for the default Firebase app.
static Firestore get instance => Firestore();
Therefore you always get the data from the default project.
To fix this you need to create your firestore using the app created by FirebaseApp.configure().
So replace:
_stream = Firestore.instance.collection(collection).snapshots();
with
_stream = Firestore(app: _abnApp).collection(collection).snapshots();