what I am trying to achieve is load data from a specific collection(teacher) of my database. So I am using a function called isTeacher(). which checks if the current user's uid belongs in that collection. if not then it is a student. it stores the value in a string called value. so when I am using stream builder to load data available in their specific collection or documents, my stream builder shows circular progress and after that, it doesn't load the data. Any help is appreciated.
Thank you
`class MyClasses extends StatefulWidget {
#override
_MyClasses createState() => _MyClasses();
}
String value;
String classPassword;
List<dynamic> catchUserDetails = [];
class _MyClasses extends State<MyClasses> {
Future isTeacher() {
return FirebaseFirestore.instance
.collection('teacher')
.doc(FirebaseAuth.instance.currentUser.uid)
.get()
.then((DocumentSnapshot doc) {
value = doc.exists.toString();
print(doc.data());
print(value);
print('isteacher called in method');
});
}
#override
Widget build(BuildContext context) {
isTeacher();
return Scaffold(
body: SafeArea(
child: StreamBuilder(
stream: FirebaseFirestore.instance
.collection(value)
.doc(FirebaseAuth.instance.currentUser.uid)
.collection('class')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
} else {
final messages = snapshot.data.documents.reversed;
List<GenerateClass> messageBubbles = [];
for (var message in messages) {
final messageText = message.data()['className'];
final messageBubble = GenerateClass(
classID: messageText,
//nnouncementID: i,
);
messageBubbles.add(messageBubble);
}
return ListView(
//itemExtent: 100,
children: messageBubbles,
);
}
},
),
),
);`
Solved it by using a FutureBuilder
FutureBuilder(
future: isTeacher(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return StreamBuilder();
Related
I am trying to get data (In real-time) from my database using QuerySnapshot.
and I need to update my data as well. This is my method and I don't know how to get my documentID in this method.
class LoadData extends StatefulWidget {
const LoadData({Key? key}) : super(key: key);
#override
_LoadDataState createState() => _LoadDataState();
}
class _LoadDataState extends State<LoadData> {
//Read Data in realTime Snapshot
final Stream<QuerySnapshot> _cupCakeStream = FirebaseFirestore.instance
.collection('cupcake')
.snapshots(includeMetadataChanges: true);
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _cupCakeStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return ListView(
shrinkWrap: true,
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
print(data); //**Print collection only..I need to get documentID with each collection**
return ListTile(
title: Text(data['cupcake_name']),
subtitle: Text(data['description']),
);
}).toList(),
);
},
);
}
}
document is a DocumentSnapshot and has an id property.
So, the following should do the trick:
return ListView(
shrinkWrap: true,
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
print(data);
print(document.id); // <= Should print the doc id
return ListTile(
title: Text(data['cupcake_name']),
subtitle: Text(data['description']),
);
}).toList(),
);
Below you can see a code where I want to display data that I have collected from a registration form in Flutter.
the registration form push the data to a collection called " user " then some other documents data are pushed as:
name - email etc...
As you can see by XXXX I want that the data I retrieve from cloud firestore be shown into the widget:
Below the code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class WelcomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink,
body: MainWelcome(),
);
}
}
class MainWelcome extends StatefulWidget {
#override
_MainWelcomeState createState() => _MainWelcomeState();
}
class _MainWelcomeState extends State<MainWelcome> {
final databaseReference = Firestore.instance;
Future<QuerySnapshot> getData() async {
return await Firestore.instance.collection("user").getDocuments();
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: getData(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
snapshot.data.documents.forEach((element) {
Center(
child: Text(
'Benvenuta ${element.data["name"]}',
style: TextStyle(fontSize: 20, color: Colors.white),
),
);
});
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return Center(child: CircularProgressIndicator());
},
);
}
}
You need to use a FutureBuilder widget to display the data in the widget tree:
Create a method that returns the data:
Future<QuerySnapshot> getData() async {
return await Firestore.instance
.collection("user")
.where("email", isEqualTo: "email_here")
.getDocuments();
}
Then inside the build() method do the following:
FutureBuilder(
future: getData(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
contentPadding: EdgeInsets.all(8.0),
title:
Text(snapshot.data.documents[index].data["name"]),
);
});
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return CircularProgressIndicator();
},
),
I have an app which I want to display documents inside collection.. the collection reference is the uid of the user.
Is there a way to get current user uid and put this uid inside StreamBuilder in stream.
I have tried like so but it did not work and returned null:
class _MyAdsState extends State<MyAds> {
final FirebaseAuth _auth = FirebaseAuth.instance;
Future getCurrentUser() async {
final FirebaseUser user = await _auth.currentUser();
final uid = user.uid;
print(uid);
return uid.toString();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection("${getCurrentUser()}").snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> querySnapShot){
if(querySnapShot.hasError){
return Text('Some Error');
}
if(querySnapShot.connectionState == ConnectionState.waiting){
return CircularProgressIndicator();
}else{
final list = querySnapShot.data.documents;
return ListView.builder(
itemBuilder: (context, index){
return ListTile(
title: Text(list[index]["subject"]),
subtitle: Text(list[index]["category"]),
);
},
itemCount: list.length,
);
}
},
)
Getting the UID is an asynchronous operation, so requires a FutureBuilder.
If you want to use the UID to then build a stream, you'll need to have a FutureBuilder for the UID, and then inside of that a StreamBuilder for the stream from the database.
body: FutureBuilder(
future: FirebaseAuth.instance.currentUser(),
builder: (context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.hasData) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection(snapshot.data.uid).snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> querySnapShot){
...
},
)
}
else {
return Text('Loading user data...');
}
THANK YOU GUYS!
I was looking for this for too long now. I had the "problem" that I was recording the senderUID for a sent message only, but of course wanted the Name being displayed in the "sentFrom" field. So I had to query Firestore for the UID and pull out the email. My solution:
FutureBuilder<QuerySnapshot>(
future: _firestore.collection("users").get(),
builder: (context, futureSnapshot) {
if (!futureSnapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
Map<String, String> users = {};
final userData = futureSnapshot.data.docs;
for (var user in userData) {
users[user.id] = user.data()["email"];
}
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection("messages").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
// ignore: missing_return
final messages = snapshot.data.docs;
List<Widget> messageWidgets = [];
for (var message in messages) {
final messageText = message.data()["text"];
final messageEmail = users[message.data()["senderUID"]];
messageWidgets
.add(Text("$messageText from $messageEmail"));
}
return Column(children: messageWidgets);
},
);
},
),
I just created a map from the data and used it inside the stream builder. Is there maybe a better solution?
I want to fetch currently logged in user data. There is a field in fire_store 'useremail'. When a user logs in, I get his ID and using 'where class' I fetch the animal's data against his ID shown below:
Widget _buildBody(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('booking_tbl').where("useremail", isEqualTo: _firebaseUser.email.toString()).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return _buildList(context, snapshot.data.documents);
},
);
}
Although it is working but it shows error on as well. I need some help to fix this issue or an alternate suggestion for this (Any suggestion or kind help would be highly appreciated):
════════ Exception caught by widgets library
══════════════════════
NoSuchMethodError was thrown building UserBookingHistoryModel(dirty,
state: _UserBookingHistoryModelState#2d8c2):
The getter 'email' was called on null.
Receiver: null
Tried calling: email
Probably the problem is caused by this snippet in Firebase Auth:
void initState() {
super.initState();
widget.auth.getCurrentUser().then((firebaseUserId) {
setState(() {
authStatus = firebaseUserId == null
? AuthStatus.notSignedIn
: AuthStatus.signedIn;
});
});
}
The full code of bookings.dart is here:
class _UserBookingHistoryModelState extends State<UserBookingHistoryModel> {
FirebaseAuth _auth;
FirebaseUser _firebaseUser;
#override
void initState() {
super.initState();
_auth = FirebaseAuth.instance;
_getCurrentUser();
}
_getCurrentUser () async {
_firebaseUser = await FirebaseAuth.instance.currentUser();
setState(() {
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _buildBody(context),
);
}
Widget _buildBody(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('booking_tbl').where("useremail", isEqualTo: _firebaseUser.email.toString()).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return _buildList(context, snapshot.data.documents);
},
);
}
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return ListView(
padding: const EdgeInsets.only(top: 5.0),
children: snapshot.map((data) => _buildListItem(context, data)).toList(),
);
}
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
return Padding(
key: ValueKey(record.animal),
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
),
child: new ListTile(
title: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Text(
"${record.animal} Slaughtering",
style: new TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
),
],
),
)
),
);
}
}
class Record {
final String animal;
final String user;
final DocumentReference reference;
Record.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['animal'] != null),
assert(map['user'] != null),
animal = map['animal'],
user = map['user'];
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
#override
String toString() => "Record<$animal:$user>]";
}
You need to do the following:
Stream<QuerySnapshot> getData() async*{
FirebaseUser firebaseUser = await FirebaseAuth.instance.currentUser();
yield* Firestore.instance.collection('booking_tbl').where("useremail", isEqualTo: firebaseUser.email.toString()).snapshots();
}
Then inside the StreamBuilder use getData():
return StreamBuilder<QuerySnapshot>(
stream: getData(),
builder: (context, snapshot) {
//....
The getData() method is asynchronous, since you are using a StreamBuilder then you need to return a Stream therefore you use the async* keyword, and you emit the result using yield*
I am building a flutter app and using cloud-firestore,
this is how my database looks like
I want a function that retrieves all documents in the collection called "Driver List" in an array of strings
that what I had already used but it gets them back in a listview in a new screen
class DriverList extends StatelessWidget {#overrideWidget build(BuildContext context) {
return new StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('DriverList').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text('Loading...');
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document['name']),
subtitle: new Text(document['phone']),
);
}).toList(),
);
},
);
}
}
This has some additional logic to remove potentially duplicate records, but you can use something like the following to retrieve data from Firestore.
We get access to a collection reference, then list the results of the query, then create local model objects for the data returned by Firestore, and then we return the a list of those model objects.
static Future<List<AustinFeedsMeEvent>> _getEventsFromFirestore() async {
CollectionReference ref = Firestore.instance.collection('events');
QuerySnapshot eventsQuery = await ref
.where("time", isGreaterThan: new DateTime.now().millisecondsSinceEpoch)
.where("food", isEqualTo: true)
.getDocuments();
HashMap<String, AustinFeedsMeEvent> eventsHashMap = new HashMap<String, AustinFeedsMeEvent>();
eventsQuery.documents.forEach((document) {
eventsHashMap.putIfAbsent(document['id'], () => new AustinFeedsMeEvent(
name: document['name'],
time: document['time'],
description: document['description'],
url: document['event_url'],
photoUrl: _getEventPhotoUrl(document['group']),
latLng: _getLatLng(document)));
});
return eventsHashMap.values.toList();
}
Source: https://github.com/dazza5000/austin-feeds-me-flutter/blob/master/lib/data/events_repository.dart#L33
Getting one time data:
var collection = FirebaseFirestore.instance.collection('DriverList');
var querySnapshot = await collection.get();
for (var queryDocumentSnapshot in querySnapshot.docs) {
Map<String, dynamic> data = queryDocumentSnapshot.data();
var name = data['name'];
var phone = data['phone'];
}
Getting data each time it changes, using a StreamBuilder:
StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance.collection('DriverList').snapshots(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text('Error = ${snapshot.error}');
if (snapshot.hasData) {
final docs = snapshot.data!.docs;
return ListView.builder(
itemCount: docs.length,
itemBuilder: (_, i) {
final data = docs[i].data();
return ListTile(
title: Text(data['name']),
subtitle: Text(data['phone']),
);
},
);
}
return Center(child: CircularProgressIndicator());
},
)
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class LoadDataFromFirestore extends StatefulWidget {
#override
_LoadDataFromFirestoreState createState() => _LoadDataFromFirestoreState();
}
class _LoadDataFromFirestoreState extends State<LoadDataFromFirestore> {
#override
void initState() {
super.initState();
getDriversList().then((results) {
setState(() {
querySnapshot = results;
});
});
}
QuerySnapshot querySnapshot;
#override
Widget build(BuildContext context) {
return Scaffold(
body: _showDrivers(),
);
}
//build widget as prefered
//i'll be using a listview.builder
Widget _showDrivers() {
//check if querysnapshot is null
if (querySnapshot != null) {
return ListView.builder(
primary: false,
itemCount: querySnapshot.documents.length,
padding: EdgeInsets.all(12),
itemBuilder: (context, i) {
return Column(
children: <Widget>[
//load data into widgets
Text("${querySnapshot.documents[i].data['activation']}"),
Text("${querySnapshot.documents[i].data['car1']}"),
Text("${querySnapshot.documents[i].data['car2']}"),
Text("${querySnapshot.documents[i].data['car5']}"),
Text("${querySnapshot.documents[i].data['name']}"),
Text("${querySnapshot.documents[i].data['phone']}"),
],
);
},
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}
//get firestore instance
getDriversList() async {
return await Firestore.instance.collection('DriversList').getDocuments();
}
}
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StreamBuilder(
stream:
FirebaseFirestore.instance.collection('messages').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
}
if (snapshot.hasData) {
final messages = snapshot.data!.docs;
List<Text> messageWigdets = [];
for (var message in messages) {
final messageText = message['text'];
final messageSender = message['sender'];
final messageWigdet =
Text('$messageText from $messageSender');
messageWigdets.add(messageWigdet);
}
return Expanded(
child: ListView(
children: [...messageWigdets],
),
);
}
return const CircularProgressIndicator.adaptive();
},
),