1

I have a problem, it is that i have to reload app to refresh the widget (TableCalendar), i know that there is a setState to detect changes and reload but... i supose i have to execute again the method getData where i have all the information about the events and reload the calendar but i don't know how can i do it.

Here is the init state where i call getData to get the data.

 void initState() {
    super.initState();
    getData();

    Future.delayed(const Duration(seconds: 3), () {
      _selectedDay = _focusedDay;
      _selectedEvents = ValueNotifier(_getEventsForDay(_selectedDay!));
      FirebaseFirestore.instance
          .collection("usuaris")
          .doc(usuari!.uid)
          .get()
          .then((value) {
        this.usuariActual = ModelUsuari.fromMap(value.data());
        setState(() {});
      });
    });
  }

getData is in other class

Future<void> getData() async {
  User? usuari = FirebaseAuth.instance.currentUser;
  final allDataGlobal = <RegistreSentiment>[];
  CollectionReference collectionRef = FirebaseFirestore.instance
      .collection('usuaris')
      .doc(usuari!.uid)
      .collection('Registre sentiments');

  final registresRef = collectionRef.withConverter<RegistreSentiment>(
    fromFirestore: (snapshot, _) =>
        RegistreSentiment.fromMapData(snapshot.data()!),
    toFirestore: (notaActual, _) => notaActual.toMap(),
  );

  List<QueryDocumentSnapshot<RegistreSentiment>> registresUsuari =
      await registresRef.get().then((snapshot) => snapshot.docs);

  registresUsuari.forEach((doc) => {
        allDataGlobal.add(doc.data()),
        // convert this Map to your custom object and add it to your list
      });

  for (var dataRegistre in allDataGlobal) {
    DateTime tempDate = DateTime.fromMicrosecondsSinceEpoch(
        dataRegistre.dataRegistreTS!.microsecondsSinceEpoch);
    // dataRegistre.dataRegistre = DateFormat("yyyy-MM-dd").format(tempDate);
    dataRegistre.dataRegistre = tempDate;
  }

  for (var element in allDataGlobal) {
    _kEventSource[DateTime(
      element.dataRegistre!.year,
      element.dataRegistre!.month,
      element.dataRegistre!.day,
    )] = _kEventSource[DateTime(
              element.dataRegistre!.year,
              element.dataRegistre!.month,
              element.dataRegistre!.day,
            )] !=
            null
        ? [
            ...?_kEventSource[DateTime(
              element.dataRegistre!.year,
              element.dataRegistre!.month,
              element.dataRegistre!.day,
            )],
            element
          ]
        : [element];
  }
}

Then i should press the button to add event and reload both... getData and the tablecalendar This part of code is where i have to reload or refresh both.

 Padding(
                        padding: EdgeInsets.only(bottom: 40),
                        child: FloatingActionButton(
                          onPressed: () {
                            Comment = commentController.text;
                            submit();
                            SaveToFirebase(
                                Comment, elecc, _selectedDay!);
                          },
                          
                          child: const Icon(Icons.save),
                          backgroundColor: Colors.green,
                        ),
                      )
                    ],

The main problem is that GetData, have an method that is async

  List<QueryDocumentSnapshot<RegistreSentiment>> registresUsuari =
      await registresRef.get().then((snapshot) => snapshot.docs);

When the compiler arrives at this part, while it is being processed, it passes to the method below, which is to put the events on the calendar, but of course if the await has not finished yet, the method is empty, so they will not be loaded.

This is the method:

final kEvents = LinkedHashMap<DateTime, List<RegistreSentiment>>(
  equals: isSameDay,
  hashCode: getHashCode,
)..addAll(_kEventSource);

So.. That's why at the begining of the code i use a Future.delayed because i have to wait to the getData, but if i don't put the Delay, happens what i said.

Imagetounderstand

If you help me you will make me very happy... i spent a lot of hours with this... <3

1 Answers1

1

You must remove the then method, you are already using await, your query will wait for the docs to return.

  var querySnapshot = await registresRef.get();
  List<QueryDocumentSnapshot<RegistreSentiment>> registresUsuari = querySnapshot.docs;

Remove the forEach it is synchronous, only the interaction inside it is async, but the return is sync. Use for which is async.

for(var doc in registresUsuari){
  allDataGlobal.add(doc.data());
}
Chance
  • 1,497
  • 2
  • 15
  • 25
  • It does the same... It started but go to the kEvents where is null because it doesn't get the results yet. The method don't wait, go ahead and continue with the code – Albert mora costillo Oct 11 '22 at 00:19
  • Right but I didn't understand this RegistreSentiment in the , in the List>. What is he? It is a typedef for Map. – Chance Oct 11 '22 at 00:29
  • I updated the answer, see if it solves, if possible add break point in the places where you are receiving the null, so you can check all the variables. – Chance Oct 11 '22 at 00:34
  • Grab the info from firebase and from this list we transform each object in the list to type RegistreSentiment – Albert mora costillo Oct 11 '22 at 07:39
  • basicaly the await doesn't work and the method don't wait until it finishes. – Albert mora costillo Oct 11 '22 at 12:47
  • I posted an image if it will be better to understand... – Albert mora costillo Oct 11 '22 at 13:13
  • Look I made a test in the same format as your function. Until the `for(var element in allDataGlobal)` there are no problems, all pauses are respected, so the problem is not in the await, probably in the section that assembles the events list, as I said add break point in the place where you are seeing a null value , do it using vscode or android studio is pretty simple. – Chance Oct 11 '22 at 22:17