I'm new to Flutter and Dart.
I have a Stateful class with the _user variable.
I'd like to use this variable in a query I'm making to Firestore.
Neither "this" nor "_user" are available inside _usersStream (I believe this is a factory).
How can I access _user?
class _UserTermsState extends State<UserTerms> {
late User _user;
bool _isSigningOut = false;
final Stream<QuerySnapshot> _usersStream = FirebaseFirestore.instance
.collection('somecol')
.where('uid', isEqualTo: this._user.uid)
.orderBy('createdAt', descending: true)
.snapshots();
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _usersStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
return Scaffold( and so on...
You can't access instance member '_user' in an initializer.
Try this:
class _UserTermsState extends State<UserTerms> {
late User _user;
bool _isSigningOut = false;
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('somecol')
// make sure _user is defined before build is called.
.where('uid', isEqualTo: _user.uid)
.orderBy('createdAt', descending: true)
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
Related
When I try to use the FutureBuilder Widget to await a boolean value from my Firebase Database, it is not returning the values I want.
The return LoginPage() it's working fine.
Both print1 and print2 are being executed.6
Widget build(BuildContext context) {
return StreamBuilder(
stream: Auth().authStateChanges,
builder: (context, snapshot) {
if (snapshot.hasData) {
return FutureBuilder(
future: _getCurrentUserData(),
builder: ((context, AsyncSnapshot<bool> hasAccountSetup) {
if (hasAccountSetup.data == true) {
print("print1");
return MyHomePage();
} else {
print("print2");
return AccountSetup();
}
}));
} else {
return LoginPage();
}
},
);
}
Future<bool> _getCurrentUserData() async {
final DocumentSnapshot userDoc = await FirebaseFirestore.instance
.collection('Users')
.doc(Auth().currentUser!.uid)
.get();
return userDoc.get('HasSetupAccount');
}
If HasSetupAccount is a field from your firestore database then try this:
Future<bool> _getCurrentUserData() async {
final DocumentSnapshot userDoc = await FirebaseFirestore.instance
.collection('Users')
.doc(Auth().currentUser!.uid)
.get();
Map<String, dynamic> data = docSnapshot.data()!;
//HasSetupAccount should be the name of the field you want to access
return data['HasSetupAccount'];
}
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
class ListStudentPage extends StatefulWidget {
State<StatefulWidget> createState() {
return _ListStudentPage();
}
}
class _ListStudentPage extends State<ListStudentPage> {
final Stream<DocumentSnapshot<Map<String, dynamic>>> productsStream =
FirebaseFirestore.instance
.collection('Categories')
.doc('Pharmacy')
.snapshots();
#override
Widget build(BuildContext context) {
return StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: productsStream,
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot<Map<String, dynamic>>> snapshot) {
if (snapshot.hasError) {
print('Something went Wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
final List productDocs = [];
snapshot.data!.docs.map((DocumentSnapshot document) {
Map a = document.data() as Map<String, dynamic>;
productDocs.add(a);
a['id'] = document.id;
}).toList();
});
}
}
I am getting this error "The getter 'docs' isn't defined for the type 'DocumentSnapshot<Map<String, dynamic>>" in the line right below( snapshot.data!.docs.map((DocumentSnapshot document,docs here is highlighted with a red underline)
) , where I created an empty list , can anyone please tell me why I am getting this error and how can I fix it .
Use QuerySnapshot<Map<String, dynamic>> , because its used when your getting a stream or a list which is the case for you now, while use DocumentSnapshot<Map<String, dynamic>> when your getting a single item.
Your productsStream refers to a single document named Pharmacy under the Category collection. Since you're reading only a single document, there is no need for the snapshot.data!.docs.map and you can just return a single widget for the one document you loaded.
Something like this for example:
return StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: productsStream,
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot<Map<String, dynamic>>> snapshot) {
if (snapshot.hasError) {
print('Something went Wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return Text(snapshot.data!.get('id')); // 👈
});
I have a boolean value in firestore, i need to set a condition based on this boolean. I am trying to get this boolean from firestore and then using it in my futurebuilder but i am always getting null even if i can see values are there in firestore. Please help.
Future<bool> getUser() async {
dynamic data;
bool isUser=false;
final DocumentReference document =
FirebaseFirestore.instance.collection('users').doc(uida).collection('pre').doc();
isUser = await document.get().then<dynamic>(( DocumentSnapshot snapshot) async{
data =snapshot.data;
final data1 = data.map((doc) => doc['enrolled']);
print(data1.toString());
if (data1==true){
setState(() {
isUser = true;
});}
});
return isUser;
}
Widget
return FutureBuilder(
future: getUser(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (snapshot.data == true)
return Text(snapshot.data.toString());
When using asynchronous code, it is better to either use async and await or use then. In your case async and await will give a more readable code.
For your getUser function this would be something like:
Future<bool> getUser() async {
dynamic data;
bool isUser=false;
final DocumentReference document =
FirebaseFirestore.instance.collection('users').doc(uida).collection('pre').doc();
isUser = await document.get()
data = snapshot.data;
final data1 = data['enrolled'];
print(data1.toString());
if (data1==true){
setState(() {
isUser = true;
});}
});
return data1;
}
And for the Futurebuilder, it is better to check whether the snapshot contains data, by using snapshot.hasData like this:
return FutureBuilder(
future: getUser(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (snapshot.hasData)
if (snapshot.data ==true){
return Text(snapshot.data.toString());
} else {
return Text('still waiting for data...')
See https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html for a much better explanation.
You can use the code below it will solve your issue, but check two things do you have all required permissions to fetch data from firebase and also check if the document id is correct ? you can use use if(snapshot.data!.exists) to check if the document exist in the current collection
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
class TestClass extends StatefulWidget {
const TestClass({Key? key}) : super(key: key);
#override
_TestClassState createState() => _TestClassState();
}
class _TestClassState extends State<TestClass> {
final _auth = FirebaseAuth.instance;
final FirebaseFirestore _fireStore = FirebaseFirestore.instance;
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<DocumentSnapshot>(
future: _fireStore
.collection('users').doc(uida).collection('pre').doc(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(child: Text(snapshot.data!['enrolled'].toString()));
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
);
}
}
I am trying to pass parameters into the future instance but I encounter the "error instance member can't be accessed in an initializer" for _getData at future: _getData even though I have initialized it in initState.
class _DisplayListState extends State<DisplayList> {
late Future<QuerySnapshot> _getData;
Future<QuerySnapshot> getData(String value)async{
return await FirebaseFirestore.instance
.collection('x')
.where('a', isEqualTo: value)
.get();
}
#override
void initState(){
super.initState();
_getData = getData(widget.value);
}
Widget displayList = FutureBuilder(
future: _getData,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
return Container();
},
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: displayList,
);
}
}
I remove the the parameters for getData thinking that I should simplify the problem first and tried future: getData() but I encoutered the same error.
The only way that I don't encounter the error is if I do this - future: FirebaseFirestore.instance.collection('x').where('a', isEqualTo: 'something').get() for FutureBuilder. But this means I cannot pass parameters and I would prefer to use a function/variable for this over the long line of code.
future: FirebaseFirestore.instance.collection('x').where('a', isEqualTo: value).get() where value=widget.value is initialized in initState will give me the same error.
You can use a method for displayList instead of a variable.
You can change this:
Widget displayList = FutureBuilder(
future: _getData,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
return Container();
},
);
to this:
Widget getDisplayList() => FutureBuilder(
future: _getData,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
return Container();
},
);
And in the Scaffold's body, use the method like this:
body: getDisplayList()
Hi I am now trying to get Stream<List<Post>> with fetchAllPosts function.
toPosts is a Transformer that turns QuerySnapshot into a Stream<List>.
// firebase_provider.dart
Stream<List<Post>> fetchAllPosts() {
return _firestore
.collection('Posts')
.orderBy('commenttime', descending: true)
.snapshots()
.transform(toPosts);
}
This Stream<List> value will be used as a ListView within the StreamProvider in feed_page.dart
// feed_page.dart
Widget build(BuildContext context) {
return StreamProvider<List<Post>>.value(
value: firestoreProvider.fetchAllPosts()
However, if the snapshot is empty, I want to handle it differently in feed_page.dart(not in ListView)
How should I handle this? The following method is what I've tried, but I'm not sure what to put in the last else statement in this case. Or I think there will be a better way
Stream<List<Post>> fetchAllPosts2() {
if (_firestore
.collection(COLLECTION_POSTS)
.orderBy(KEY_POSTTIME, descending: true)
.snapshots()
.length
.toString() !=
"0") {
return _firestore
.collection(COLLECTION_POSTS)
.orderBy(KEY_POSTTIME, descending: true)
.snapshots()
.transform(toPosts);
} else {
return ???????????;
}
}
Help me plz ;-)
Did you try FutureBuilder approach ?
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: FutureBuilder<List<String>>(
future: fetchFunction(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
else if (snapshot.connectionState == ConnectionState.done) {
return snapshot.data.isEmpty?Text("empty list"):ListView(children: [...snapshot.data.map.((post)=>Text(post)),],);
}
},
),
),
);
}
}