getOneGoalieInformationnFromID() is only doing a loop one time in this for loop.
Future<void> getGoaliesInformationFromID() {
for (var goalieID = 0;
goalieID < goaliesOfCurrentUserID.length;
goalieID++) {
getOneGoalieInformationnFromID**(goaliesOfCurrentUserID[goalieID])
.whenComplete(() {
getSelectedGoalieStats();
});
}
super.initState();
}
Here is the function getOneGoalieInformationnFromID() only doing the loop once:
Future<void> getOneGoalieInformationnFromID(goalieID) async {
try {
setState(() {
loading = true;
});
await fDb
.collection('users')
.where('__name__', isEqualTo: goalieID)
.get()
.then((QuerySnapshot querySnapshot) {
print(querySnapshot.docs);
querySnapshot.docs.forEach((doc) {
setState(() {
...
What is causing that?
Your getOneGoalieInformationnFromID function is also a Future function you called inside the loop and that will call once
in getGoaliesInformationFromID function, instead of for-loop you should use map-loop and use for waiting function Future.wait
Future<void> getGoaliesInformationFromID() async{
Future.wait( await goaliesOfCurrentUserID.map(goalieId)async{
await getOneGoalieInformationnFromID**(goaliesOfCurrentUserID[goalieID])
.whenComplete(() {
getSelectedGoalieStats();
});
});
}
Related
I have a model and I want to use my services file to fill it from Firebase but I don't know how to do that ?
I am filling it with FutureBuilder that's okey. But it is exhausting me.
Here is my model:
class ReviewModel {
String? uid;
String? userID;
String? comment;
dynamic rate;
ReviewModel({
this.uid,
this.userID,
this.comment,
this.rate,
});
Map<String, dynamic> toMap() {
return {
'uid': uid,
'userID': userID,
'comment': comment,
'rate': rate,
};
}
factory ReviewModel.fromMap(Map<String, dynamic> map) {
return ReviewModel(
uid: map['uid'],
userID: map['userID'],
comment: map['comment'],
rate: map['rate'],
);
}
factory ReviewModel.fromDatabase(
DocumentSnapshot snapshot, Map<String, dynamic> map) {
return ReviewModel(
uid: snapshot['uid'],
userID: map['userID'],
comment: map['comment'],
rate: map['rate'],
);
}
}
Code is Following below,
Future<ReviewModel> getSalonReviews(String salonUID) async {
CollectionReference aRef = FirebaseFirestore.instance
.collection("salons")
.doc(salonUID)
.collection('bucket')
.doc('reviewbox')
.collection('reviews');
dynamic _doc;
var snapshot;
try {
await aRef.get().then((querySnapshot) => {
for (var dummyDoc in querySnapshot.docs)
{
_doc = dummyDoc.data(),
print(_doc),
}
});
return ReviewModel.fromMap(_doc);
} on FirebaseException catch (e) {
Get.snackbar("Hata", e.code);
rethrow;
}
}
This code is not returning my ReviewModel.
Also I am using GetX and this is my GetX code:
final Rx<ReviewModel> _reviewModel = ReviewModel().obs;
ReviewModel get reviewModel => _reviewModel.value;
set reviewModel(ReviewModel value) => _reviewModel.value;
Future fillReviewModel(String uid) async {
SalonController.instance.reviewModel =
await FakeService().getSalonReviews(uid);
}
it return me this:
And this is my Firebase docs:
How do I achive my ReviewModel with Obx. If I try it, it returns null.
You don't have to return a model you'll do something like this in your prvoider file:
List _reviews = [];
List get reviews => [..._reviews];
// IN your future void function
Future<void> myFunction () async{
myReviews = ...result of forEach;
// now update _reviews
_reviews = [...myReviews];
//And then notify listeners
notifylisteners;
}
And then in your futurebuilder
FutureBuilder(future: Provider.of<myClass>(context, listen:false).myFunction(),
builder:(context, snapshot){
// check the state like the following
if(snapshot.connectionState == ConnectionState.done){
final myValues = Provider.of<myClass>(context, listen:false).reviews;
...do something
return your_values}
if(snapshot.connectionState == ConnectionState.waiting){return progressIndicator}
})
In the last update of cloud_firestore, I get an error when I run the app with the old code. How can I convert a Stream<QuerySnapshot<Map<String, dynamic>>> to a List?
I have this code and I get null values:
Stream<List<Model>> getReviews(String id) {
try {
return _collectionReference.doc(id).collection('reviews').orderBy('date', descending: true).snapshots().map((reviews) => reviews.docs.map((review) => Model.fromJson(review.data())));
} catch (error) {
return error.message;
}
}
If you just want to get the List<Model> use a get call and await the result before returning the List<Model> like here:
Future<List<Model>> getReviews(String id) {
try {
QuerySnapshot querySnapshot=await _collectionReference.doc(id).collection('reviews').orderBy('date', descending: true).get();
List<Model> result;
querySnapshot.docs.forEach((doc) {
print(doc["first_name"]);
result.add(Model.fromJson(review.data()));
});
return result;
} catch (error) {
return error.message;
}
Make sure to call getReviews as asynchronous.
I have a stream of posts that works fine but I want to check whether the current user likes a particular post. To implement the latter, I have to get info from Firestore which is a future. I have tried using yield* but it doesn't work. My code is as below;
CollectionReference posts = FirebaseFirestore.instance.collection('posts');
String userId = FirebaseAuth.instance.currentUser?.uid;
Stream<List<Post>> get allPosts async* {
yield* posts.snapshots().map((snapShot) => snapShot.docs.map((document) {
DocumentSnapshot isLikedByCurrentUser = await FirebaseFirestore //The await here is erroneous and doesnt work
.instance
.collection('likes')
.doc(this.userId + '_' + document.id)
.get();
return Post.fromJson(
document.id, document.data(), isLikedByCurrentUser.exists);
}).toList());
}
This is more complicated than it needs to be. I'd unwrap the map calls to for loops:
Stream<List<Post>> get allPosts async* {
for (var snapshot in posts.snapshots()) {
var element = <Post>[];
for (var document in shapshot.docs) {
DocumentSnapshot isLikedByCurrentUser = await FirebaseFirestore
.instance
.collection('likes')
.doc(this.userId + '_' + document.id)
.get();
element.add(Post.fromJson(
document.id, document.data(), isLikedByCurrentUser.exists));
}
yield element;
}
}
You can even use a list literal, if you don't mind inlining the isLikedByCurrentUser variable:
Stream<List<Post>> get allPosts async* {
for (var snapshot in posts.snapshots()) {
yield <Post>[
for (var document in shapshot.docs)
Post.fromJson(
document.id,
document.data(),
(await FirebaseFirestore.instance
.collection('likes')
.doc(this.userId + '_' + document.id)
.get())
.exists)
];
}
}
This is how I have re-written it based on this answer by jamesdlin.
Future<List<Post>> _postFromSnapshot(QuerySnapshot snapshot) async {
var futures = snapshot.docs.map((doc) async {
DocumentSnapshot isLikedByCurrentUser = await FirebaseFirestore.instance
.collection('likes')
.doc(this.userId + '_' + doc.id)
.get();
return Post.fromJson(
doc.id, doc.data(), isLikedByCurrentUser.exists);
}).toList();
return await Future.wait(futures);
}
Stream<List<Post>> get allPosts {
return posts.snapshots().asyncMap(_postFromSnapshot);
}
My web application requires me to use firestore listener for a document jkl. Instead of printing the updated value once, it is repeatedly printing the value even though there is no update in the document jkl.
void switchListener() async
{
_listener = Firestore.instance
.collection('abc')
.document('def')
.collection('ghi')
.document('jkl')
.snapshots()
.listen((data) => listenerUpdate(data));
}
void listenerUpdate(data)
{
String number = data['URL'];
setState(() {
_totalDocs = number;
});
}
Can I get some help on this.
Updated
The listener is activated only after clicking on a button.
onPressed: () {
switchListener();
},
void switchListener() async {
_listener = Firestore.instance
.collection('abc')
.document('def')
.collection('jkl')
.document('mno')
.snapshots()
.distinct()
.listen((data) => listenerUpdate(data));
_listener.cancel();
}
void listenerUpdate(data) {
String number = data['physicianNote'];
String url = data['signedURL'];
setState(() {
_totalDocs = number;
_signedurl = url;
});
print("totalDoc: "+_totalDocs);
print("url: "+_signedurl);
js.context.callMethod("open", [signedurl]);
}
You can try to add the distinct() method after the snapshots() method which
skips data events if they are equal to the previous data event. You can find out more from the official docs.
void switchListener() async
{
_listener = Firestore.instance
.collection('abc')
.document('def')
.collection('ghi')
.document('jkl')
.snapshots()
.distinct() // Will only emit if `snapshots()` emits different data
.listen((data) => listenerUpdate(data));
}
void listenerUpdate(data)
{
String number = data['URL'];
setState(() {
_totalDocs = number;
});
}
I try to lint for my Flutter project, I have a class API to log in and log out google account, Linter prefers to remove static before these methods (login with Google and sign out). I cannot call these functions in view. Here my code:
API.dart
class FBApi {
FBApi(this.firebaseUser);
...
Future<FBApi> signInWithGoogle() async {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
...
}
Future<void> signOut() async {
await _auth.signOut().then((_) {
print('***** log out...what the hell?');
_googleSignIn.disconnect();
_googleSignIn.signOut();
// Navigator.of(context).pushNamedAndRemoveUntil("/login", ModalRoute.withName("/home"));
});
}
}
Login.dart error above
Future<bool> _loginUser() async {
final FBApi api = await FBApi.signInWithGoogle();---> error
if (api != null) {
return true;
} else {
return false;
}
}
Logout.dart
Future<void> _signOut() async {
try {
await FBApi.signOut();
} catch (e) {
print(e);
}
}
await FBApi.signInWithGoogle();---> error
should be
await FBApi().signInWithGoogle();
You first need to create an instance () to call an instance method.
Alternatively you can change
Future<FBApi> signInWithGoogle() async {
to
static Future<FBApi> signInWithGoogle() async {
to make signInWithGoogle available without creating an instance first.
I don't know what the intention actually is.