Search code examples
firebasefluttergoogle-cloud-firestorestream

Firestore futures


This is my next step in learning flutter and Firebase. (I have migrated all my code to Dart 2). I am getting data from a Firestore collection with this code:

List<Event> _getEventsForDay(DateTime day) {
    // kEvents is a linkedHashMap
    for (int i = 0; i < eventDoc.length; i++ ) {
      DateTime eventDate = eventDoc[i].eventDate;
      DateTime eventDateUTC = eventDate.toUtc();
      if (day.year == eventDate.year && day.day == eventDate.day && day.month == eventDate.month) {
        List<Event> eventList = [];
        eventList.add(eventDoc[i].agencyId);
        eventList.add(eventDoc[i].agentId);
        eventList.add(eventDoc[i].eventDate);
        eventList.add(eventDoc[i].eventDescription);
        eventList.add(eventDoc[i].eventDuration);
        eventList.add(eventDoc[i].eventName);
        eventList.add(eventDoc[i].eventStartTime);
        //print('kEvents: $kEvents');
        return (kEvents.putIfAbsent(eventDateUTC, () => eventList))??[];

      }
    }
    return [];
  }

I am getting a runtime error on eventDoc as follows:

The following NoSuchMethodError was thrown building _BodyBuilder:
The getter 'length' was called on null.
Receiver: null
Tried calling: length

I have declared eventDoc like this:

var eventDoc;

eventDoc is populated in this code:

StreamBuilder(
            stream: _db.collection('agency').doc(globals.agencyId).collection('event')
              .where('eventDate', isGreaterThanOrEqualTo: kFirstDay)
              .where('eventDate', isLessThanOrEqualTo: kLastDay)
                    .snapshots().map((snapshot) => snapshot.docs
              .map((document) => Event.fromFirestore(document.data()))
              .toList()),
            builder: (context, AsyncSnapshot <List<Event>> eventsSnapShot) {
              if (eventsSnapShot.hasData) {
                eventDoc = eventsSnapShot.data; <<<<< eventDoc populated
                return _buildTableCalendar();
              } else {
                return CircularProgressIndicator();
              }
            },
          ),

I am calling _getEventsForDay() in the eventLoader: property here:

Widget _buildTableCalendar() {
return TableCalendar(
      firstDay: kFirstDay,
      lastDay: kLastDay,
      focusedDay: _focusedDay,
      selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
      locale: 'en_US',
      eventLoader: (day) {
        return _getEventsForDay(day);
      },

I'm sure I am declaring eventDoc incorrectly but I don't know how it should be declared. Please help.


Solution

  • The error means that you are trying to iterate a list that is null.

    The getter 'length' was called on null.

    You can solve this error by two options:

    Option 1

    You are giving the snapshot data to your eventDoc var, but you need to update the state to notify that variable has changed

    setState(() => eventDoc = eventsSnapShot.data );
    

    Option 2

    Other solution is pass the data to your methods

    StreamBuilder(
            stream: _db.collection('agency').doc(globals.agencyId).collection('event')
              .where('eventDate', isGreaterThanOrEqualTo: kFirstDay)
              .where('eventDate', isLessThanOrEqualTo: kLastDay)
                    .snapshots().map((snapshot) => snapshot.docs
              .map((document) => Event.fromFirestore(document.data()))
              .toList()),
            builder: (context, AsyncSnapshot <List<Event>> eventsSnapShot) {
              if (eventsSnapShot.hasData) {
                if ( eventsSnapShot.data != null ) {
                  return _buildTableCalendar(eventsSnapShot.data); // Passing the data
                }
              } 
              return CircularProgressIndicator();
            },
          ),
    
    // Methods
    
    Widget _buildTableCalendar( List<Event> events ) {}
    
    List<Event> _getEventsForDay( DateTime day, List<Event> event ) {}