Rebuild widgets when a subcollection recieves data in another widget - firebase

I have 6 widgets that all share the same data with only one receiving the data from the stream
AllClasses() //displays all of classes and is the start of getting the data from the stream
ClassList(data) //displays nothing but builds the list view and holds the index of what class is to be displayed in classtile widget
ClassTile(data) //presents the data from the index of the data passed in from ClassList
ClassPage(data) //when a classtile is clicked this screen is presented
HomeworksList(data) //goes to this widget when the homeworks button is clicked shows all the homeworks that are available for the specific class clicked on
HomeworkTile(data) // shows the tile for each homework
As you can see I get the data once then pass it down the widget tree multiple times. What has become an issue is that when I am showing the homework list which is 5 widgets down the widget tree from where the data is coming from I have the option to add another homework to the homework list. technically adding it to the firestore database.
The problem is that when I add a Homework it does not refresh the data or rebuild any widgets until I go all the way back to the "AllClasses()" widget.
so to reiterate, I have a widget that shows all of the homeworks and in this widget you are able to add a homework and when you do it updates the subcollection, but does not rebuild the widget that shows all of the homeworks until I go back a couple widgets from where the data is first grabbed
the database schema is set up like this:
Classes {
subcollections:
Homework {
...
}
fields:
}
perhaps its the way I have my database and instead I should have a Homeworks collection that is outside of everything. or maybe its because I am using a generator future to produce the same thing as a stream by using a never ending while loop. either way I don't understand streams enough to understand what to do next, I have been working on this since 8am today and I have tried just about everything in my power. I may just use Homeworks as a seperate collection instead of a subcollection the problem with this is knowing which class I am in when I click on homework.
Stream<List<ClassData>> get fetchClassdata async* {
QuerySnapshot snapshot = await classesCollection.getDocuments();
// while (true) {
List<ClassData> _classList = List<ClassData>();
await Future.forEach(snapshot.documents, (element) async {
QuerySnapshot pre = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Pre")
.getDocuments();
QuerySnapshot homeworksSnapshot = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Homework")
.getDocuments();
QuerySnapshot notesSnapshot = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Notes")
.getDocuments();
QuerySnapshot testsSnapshot = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Tests")
.getDocuments();
List<Preq> _preList = List<Preq>();
List<Homework> _homeworkList = List<Homework>();
List<Note> _notesList = List<Note>();
List<Test> _testsList = List<Test>();
pre.documents.forEach((preClass) {
Preq preqData = Preq.fromMap(preClass.data);
if (preClass.data != null) {
_preList.add(preqData);
}
});
homeworksSnapshot.documents.forEach((hwork) {
Homework homeworkdata = Homework.fromMap(hwork.data);
_homeworkList.add(homeworkdata);
});
ClassData data = ClassData.fromMap(
element.data, element.documentID, _preList, _homeworkList);
if (data != null) {
_classList.add(data);
}
});
yield _classList;
// }
}
}

Related

Flutter-Firestore: - Code to retrieve data from firestore then save/use it

I am very new to Dart, and coding in general. I have produced this code after watching tutorials on YouTube. For the most part, I have been able to troubleshoot most of my problems on my own, here I feel I need some help. I wanted to extract all the fields from a document and use it. I have tried a few codes but there is no proper solution anywhere online.
Here is the code I used to retrieve it:-
documentID = '9zjwixClgwR1Act1OlPK'
firebaseGetData(documentID){
firebaseFirestore.collection('course').doc(documentID).get().then((value) {
print(value.data());
});
}
Here is my database file structure:-
I want to store all the fields in variables and use them. please help me with the correct code, please.
There are two ways to retrieve data stored in Cloud Firestore. Either of these methods can be used with documents, collections of documents, or the results of queries:
Call a method to get the data
const docRef=doc(db,’course’,'9zjwixClgwR1Act1OlPK')
getDoc(docRef)
.then((doc) => {
console.log(doc.data(),doc.id)
})
Set a listener to receive data-change events.
To get real-time data when you set a listener, Cloud Firestore sends your listener an initial snapshot of the data, and then another snapshot each time the document changes.
const docRef=doc(db,’course’,'9zjwixClgwR1Act1OlPK')
onSnapshot(docRef,(doc) => {
console.log(doc.data(),doc.id)
})
For more information, kindly check link1 & link2
Firstly you need to create firestore instance. Your function must be async and return a Future value. Also, you can check this document.
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
Future<Map<String, dynamic>> firebaseGetData({required String documentID}) async {
DocumentSnapshot ds =
await _firestore.collection("course").doc(documentID).get();
Map<String, dynamic> data = ds.data() as Map<String, dynamic>;
print(data["videoDescription"] as String); // check if it null or not
return data;
}
// creating a instance variable
final CollectionReference firestoreInstance =
FirebaseFirestore.instance.collection('course');
void _loadUserData() async {
await firestoreInstance.doc(documentID).get().then((event) {
// you can access the values by
print(event['isDOne']);
print(event['lastViewedOn']);
print(event['lectureNo']);
print(event['videoDescription']);
print(event['videoUrl']);
});
}
call the _loadUserData() function whenever you need to fetch the data.

Firestore nodes deleted on transaction

When I add to a document using below code I will successfully be able to keep adding additional objects to the array, as long as I stay on the same screen.
void createRecord(dataMap) async {
_user = await FirebaseAuth.instance.currentUser();
var createTransaction = (Transaction tx) async {
var ds = await tx.get(db
.collection('users')
.document(_user.uid)
.collection("days")
.document(DateFormat("yyyy-MM-dd").format(dataMap['day'])));
await tx.set(ds.reference, dataMap);
};
Firestore.instance.runTransaction(createTransaction);
}
After navigating off the screen then back all objects are deleted when trying to add new ones.
When I navigate back from a screen how can I add new objects to the collection with out deleting the old ones?
Thanks.
To add a new, unique item to an array, you can use the arrayUnion operator.
Something like:
await tx.update(ds.reference, {
'breakfast': FieldValue.arrayUnion(dataMap['breakfast'][0])
});
Also see:
how to add or remove item to the the existing array in firestore ?
flutter firestore, add new object in array
How do update array values in Flutter cloud_firestore?

Not Loading the value in Real Time

I am using below code to get the total number of documents from the firestore collection and then store it to int countDocument, it does get the value accurately, but when I used to display the same value in the Flutter widget Text Widget which is nested in Scaffold, upon loading the screen it does not show the value, showing null only, only upon hot reload it shows the value on the screen.
To represent the value of countDocument in Text Widget, I did countDocument.toString()' but still it does not show the value upon initial loading of the screen
How should I resolve it?
void countDocuments() async {
StreamSubscription<QuerySnapshot> _myDoc = await Firestore.instance.collection('users').snapshots().listen((result) {
countDocument = result.documents.length;
print(countDocument);
});
You need to use a StatefulWidget, then using setState, you can change the data of the Text:
void countDocuments() async {
StreamSubscription<QuerySnapshot> _myDoc = await Firestore.instance
.collection('users')
.snapshots()
.listen((result) {
setState(() {
countDocument = result.documents.length;
});
print(countDocument);
});
}
setState will call the build method again with the new data. Inside the build method you can do the following:
Text(countDocument ?? "loading")

How to properly get data from Firebase Firestore in Flutter?

I have a Firebase Firestore database as you can see in the picture. I'd like to get every document from the questions collection with their fields.
I found the following solution on the internet:
//in this list we store the data
List adatok = [];
Future<void> getData(){
databaseReference.getDocuments().then((QuerySnapshot snapshot) {
snapshot.documents.forEach((f){
data = f.data;
adatok.add(data);
print(adatok.length);
print(adatok);
}
);
}
);
}
My problem is that when I call this function (in an onPresed() function of a button), for the first time of pressing the adatok list is empty. But when I press the button for the second time, it contains every data which I wanted to acquire.
Did I do something wrong? Is there another way to get the data?
The layout of the database
Use the code below:
List adatok = [];
Future<void> getData() async{
QuerySnapshot snapshot = await databaseReference.getDocuments();
snapshot.documents.forEach((f){
data = f.data;
adatok.add(data);
print(adatok.length);
print(adatok);
}
}
By this way, The program waits until it gets all the documents.
and then adds it to your snapshots.
Also you have to change your onPressed() function to async/await like the following:
onPressed:() async{
await getData();
/...
}
So the program waits until getData() finishes.

Flutter Firestore how to update one object in object list?

I want to remove (or change) one specific object in an object list of one Firestore document.
Is there a way to tx.update(ref,objectlist.element) directly?
Right now, I get the document snapshot, I read the object list, modify it, then tx.update the whole objectlist.
Firestore.instance.runTransaction((Transaction tx) async {
DocumentSnapshot postSnapshot = await tx.get(postRef);
if (postSnapshot.exists) {
Map<String, dynamic> myMap = Map.from(postSnapshot.data["objList"]);
myMap.remove(something);
await tx.update(postRef, <String, dynamic>{"objList": myMap}).then((x) {
print("leaving document editor");
_goBackToMain();
});
}
});
While that works, I'm worried about conflicts if two users try to update the same objectlist at the same time.

Resources