await Function does not return a value - flutter

I have created function get user and set it's data from firestore, this is the code of function getUser.
Future<User> getUser(String uid) async{
User user;
_firestore
.collection(USERS_COLLECTION)
.where("uid", isEqualTo: uid.toString())
.getDocuments()
.then((doc) {
_firestore
.document('/$USERS_COLLECTION/${doc.documents[0].documentID}')
.get()
.then((userData) {
user = User(
name: userData.data["name"],
username: userData.data["username"],
profilePhoto: userData.data["profilePic"],
);
}).catchError((e) {
print(e);
});
});
return user;
}
Then I have my profile page I have created function to set user from getUser() to current user like this:
User me;
String myUID = "t4skPFRXcLPxAWvhHpaiPOfsrPI3";
#override
void initState() {
super.initState();
setUser();
}
......
Future<void> setUser() async{
me = await userManagment.getUser(myUID);
}
But when I try to use print for example print(me.name) does not anything happen, when I try to set url of networkImage to me.profilePhoto there is an error showing tell me the url it's null.

Don't mix async-await and .then syntax. It's something that can be done, but it will more likely confuse than help. Adding the async modifier to your function is doing nothing since your function does not use await.
Consider the following options:
With .then
Future<User> getUser(String uid) {
return _firestore
.collection(USERS_COLLECTION)
.where("uid", isEqualTo: uid.toString())
.getDocuments()
.then((doc) {
return _firestore
.document('/$USERS_COLLECTION/${doc.documents[0].documentID}')
.get()
.then((userData) {
return User(
name: userData.data["name"],
username: userData.data["username"],
profilePhoto: userData.data["profilePic"],
);
}).catchError((e) {
print(e);
});
});
}
With async-await
Future<User> getUser(String uid) async{
User user;
try{
var doc = await _firestore
.collection(USERS_COLLECTION)
.where("uid", isEqualTo: uid.toString())
.getDocuments();
var userData = await _firestore
.document('/$USERS_COLLECTION/${doc.documents[0].documentID}')
.get();
user = User(
name: userData.data["name"],
username: userData.data["username"],
profilePhoto: userData.data["profilePic"],
);
}
catch(e) {
print(e);
}
return user;
}

Related

Toggling a favorites button while adding and deleting items from firestore

I want to toggle a favourites button using firestore. When i click on it initially, I want to add it to a collection, then clicking again should remove that exact item from the collection. My issue here is that, I could achieve this by setting the doc name to the title and simply delete using the title has reference. This would have an issue later on, since two products can technically have the same name. That is why I want to use the id has a reference name since it is dynamic. This is the code below.
try {
if (widget.product['isFavourited'] == true) {
String docId = widget.product.id;
// print(docId.toString());
// print(widget.product['isFavourited'].toString());
await FirebaseFirestore.instance
.collection('Products')
.doc(docId)
.update({'isFavourited': false}).then((value) async {
final CollectionReference collectionReference =
FirebaseFirestore.instance
.collection('Users')
.doc(uid)
.collection('Favourites');
await collectionReference
.doc()
.delete();
print('');
});
} else {
String docId = widget.product.id;
await FirebaseFirestore.instance
.collection('Products')
.doc(docId)
.update({'isFavourited': true}).then((value) async {
final CollectionReference collectionReference =
FirebaseFirestore.instance
.collection('Users')
.doc(uid)
.collection('Favourites');
final String id = collectionReference.doc().id;
final String itemtodelete = collectionReference.doc(id).id;
print(itemtodelete);
print(id);
await collectionReference.doc(itemtodelete).set({
'id': itemtodelete,
'title': widget.product['title'],
'price': widget.product['price'],
'about': widget.product['about'],
'description': widget.product['description'],
'imagepath': widget.product['imagepath'],
'isFavourited': widget.product['isFavourited'],
'isCarted': widget.product['isCarted'],
});
});
try is out hope this will help.
// productId is your productId = widget.product.id
// uid is your current user id
// favorite id is your each favorite documentId
Future<void> addToFavorite(String productId, String uid, favoriteId) async {
final productCollection = FirebaseFirestore.instance.collection("Products");
final favoriteCollection = FirebaseFirestore.instance.collection("Users").doc(uid).collection("Favorites");
final productDocReference = await productCollection.doc(productId).get();
if (productDocReference.exists) {
final favoriteDocReference = favoriteCollection.doc(favoriteId).get().then((favoriteDoc) {
if (!favoriteDoc.exists) {
favoriteCollection.doc(favoriteId).set({
'id': favoriteId,
'title': widget.product['title'],
'price': widget.product['price'],
'about': widget.product['about'],
'description': widget.product['description'],
'imagepath': widget.product['imagepath'],
'isFavourited': widget.product['isFavourited'],
'isCarted': widget.product['isCarted'],}).then((value){
productCollection.doc(productId).update({
"isFavourited": true
});
});
} else {
favoriteCollection.doc(favoriteId).delete().then((value) {
productCollection.doc(productId).update({
"isFavourited": false
});
});
}
});
}
}
This code worked perfectly for me, given the way I structured my function. #Adnan Khan's answer was really helpful in figuring it out. I hope this helps someone who is stuck.
Future<String> addtoFavourites(QueryDocumentSnapshot data, String uid) async {
final CollectionReference collectionReference = FirebaseFirestore.instance
.collection('Users')
.doc(uid)
.collection('Favourites');
final String id = collectionReference.doc().id;
String docId = data.id;
try {
if (data['isFavourited'] == true) {
await FirebaseFirestore.instance
.collection('Products')
.doc(docId)
.update({'isFavourited': false}).then((value) async {
print(docId);
await collectionReference.doc(docId).delete();
return 'Removed from favourites';
});
} else {
await FirebaseFirestore.instance
.collection('Products')
.doc(docId)
.update({'isFavourited': true}).then((value) async {
print(docId);
print(id);
await collectionReference.doc(docId).set({
'id': docId,
'title': data['title'],
'price': data['price'],
'about': data['about'],
'description': data['description'],
'imagepath': data['imagepath'],
'isFavourited': true,
'isCarted': data['isCarted'],
});
});
}
notifyListeners();
return 'Added to favourites';
} catch (e) {
return e.toString();
}

How to retrieve current user data from firebase?

I tried this way, but i'm getting an error.
The error:
The method 'data' isn't defined for the type 'CollectionReference'. (undefined_method at [myapp] android\app\lib\useracc.dart:32)
void getData() async{
User? user = await FirebaseAuth.instance.currentUser;
var vari =FirebaseFirestore.instance.collection("users");
setState (() {
name = vari.data()['firstname'];
}
);
}
Signup/Register Page
Future<User?> _register(String fname,String lname ,String email, String password) async{
FirebaseAuth _auth = FirebaseAuth.instance;
FirebaseFirestore _firestore = FirebaseFirestore.instance;
try {
UserCredential userCrendetial = await _auth.createUserWithEmailAndPassword(email: emailController.text, password: passwordController.text);
print("Account created Succesfull");
userCrendetial.user!.updateDisplayName(fname);
userCrendetial.user!.updateDisplayName(lname);
await _firestore.collection('users').doc(_auth.currentUser!.uid).set({
"firstname": fname,
"lastname" : lname,
"email": email,
"uid": _auth.currentUser!.uid,
});
return userCrendetial.user;
} catch (e) {
print(e);
return null;
}
}
This is the user account from where i want to fetch info:
Please help. I'm struck here a long time.
You should retrieve the currentUser document then access its data:
void getData() async{
var vari = await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser.uid)
.get();
setState (() {
name = vari.data()['firstname'];
});
}
if you've saved your user's details in firestore and its document id is the same as that of user ID (which is preferred for ease of access and control), then:
var vari =FirebaseFirestore.instance.collection("users").doc(user!.uid).get();
This gets the document of the user, and the type is DocumentSnapshot.
Map<String,dynamic> userData = vari as Map<String,dynamic>;
now userData is stored in form of Map. suppose you want to access their 'name', so the syntax now goes like userData['name'].
Similarly other fields can be accessed from variable. It's preferred to store userData in a Provider to access it's contents anywhere in your app.
Full code snippet
void getData() async{
User? user = await FirebaseAuth.instance.currentUser;
var vari =FirebaseFirestore.instance.collection("users").doc(user!.uid).get();
Map<String,dynamic> userData = vari as Map<String,dynamic>;
setState (() {
name = userData['firstname']; //or name = userData['name']
}
);
}

Mocking firebase user.reload() in flutter test

I'm trying to mock firestore call with a mocked user.
Using https://pub.dev/packages/fake_cloud_firestore and https://pub.dev/packages/firebase_auth_mocks.
but im getting the error:
NoSuchMethodError: Class 'MockUser' has no instance method 'reload' with matching arguments.
Receiver: Instance of 'MockUser'
Tried calling: reload()
Found: reload() => Future
My method:
Future<String> getHistory(
FirebaseAuth firebaseAuth, FirebaseFirestore firestore) async {
String title = "";
var user = firebaseAuth.currentUser;
user.reload();
if (user != null) {
await firestore
.collection('users')
.doc(user.uid)
.collection('history')
.get()
.then((QuerySnapshot querySnapshot) {
if (querySnapshot.docs.isNotEmpty) {
title = querySnapshot.docs.single.get('title');
}
}).catchError((error) => print(error));
}
return title;
}
and the test:
test("history", () async {
final mockFirestore = FakeFirebaseFirestore();
HistoryFirebase historyFirebase;
String historyTitle="";
final user = MockUser(
isAnonymous: false,
uid: 'someuid',
email: 'bob#somedomain.com',
displayName: 'Bob',
);
var mockFirebaseAuth = MockFirebaseAuth(mockUser: user, signedIn: true);
await instance.collection('users').doc('someuid').collection('history').add({
'title': "Title num.1",
})
await historyFirebase.getHistory(mockFirebaseAuth, mockFirestore).then((value) => historyTitle=value);
expect(historyTitle, "Title num.1");
});
Is there any way to mock the user.reload() or to ignore it ?
I contacted the developer of https://pub.dev/packages/firebase_auth_mocks and he implemented the reload () method.
everything works now

TypeError: Cannot read property 'uid' of null flutter

I'm currently facing this error message at login, my registration function works fine. but can't seem to figure out why my login keeps bringing this error. I would appreciate if I can be pointed to where my mistake is coming from.
void loginUser() async {
User user;
await _auth
.signInWithEmailAndPassword(email: email.text, password: password.text)
.then((value) {
setState(() {
loading = false;
});
return value;
}).catchError((error) {
Navigator.pop(context);
Get.defaultDialog(title: 'Error in Login');
});
if (user != null) {
readData(user).then((value) => Get.toNamed(homeRoute));
}
}
Future readData(User user) async {
FirebaseFirestore.instance
.collection('users')
.doc(user.uid)
.get()
.then((result) async {
await App.sharedPreferences.setString('uid', result.get('uid'));
await App.sharedPreferences.setString('email', result.get('email'));
await App.sharedPreferences.setString('fullname', result.get('fullname'));
await App.sharedPreferences.setString('bvn', result.get('bvn'));
});
}
Here's my Registration function
void _registerUser() async {
User user;
await _auth
.createUserWithEmailAndPassword(
email: email.text, password: password.text)
.then((value) {
user = value.user;
}).catchError((error) {
Navigator.pop(context);
Get.defaultDialog(title: 'Error in registration');
});
if (user != null) {
saveToFirestore(user).then((value) => Get.toNamed(homeRoute));
}
}
Future saveToFirestore(User user) async {
FirebaseFirestore.instance.collection('users').doc(user.uid).set({
'uid': user.uid,
'fullname': fullname.text.trim(),
'email': user.email,
'bvn': bvn.text
});
await App.sharedPreferences.setString('uid', user.uid);
await App.sharedPreferences.setString('email', user.email);
await App.sharedPreferences.setString('fullname', fullname.text);
await App.sharedPreferences.setString('bvn', bvn.text);
}
Change
User user;
await _auth
to User user = await _auth....
And in your FireStore query, use
Future readData(User user) async {
FirebaseFirestore.instance
.collection('users')
.doc(user.user.uid) // instead of user.uid
.get()
Everywhere with user.uid change it to user.user.uid.

How to check if subcollection exists in Firestore with Flutter future<bool>

I have a problem with return true/false statement from Firestore query if some sub-collection exists.
Here is my code:
Future<bool> checkIfCollectionExist(
String collectionName, String productId) async {
await _db
.collection('products')
.doc(productId)
.collection(collectionName)
.limit(1)
.get()
.then((value) {
return value.docs.isNotEmpty;
});
}
As a result I get Instance of Future<bool>, but I need true/false answer.
What I doing wrong here ?
Use
Future<bool> checkIfCollectionExist(String collectionName, String productId) async {
var value = await _db
.collection('products')
.doc(productId)
.collection(collectionName)
.limit(1)
.get();
return value.docs.isNotEmpty;
}
Or
Future<bool> checkIfCollectionExist(String collectionName, String productId) {
return _db
.collection('products')
.doc(productId)
.collection(collectionName)
.limit(1)
.get()
.then((value) {
return value.docs.isNotEmpty;
});
}