Flutter/Firebase - List<dynamic> has no instance getter 'documents'

529

Try this:

getData() {
  Stream stream1 = Firestore.instance.collection('datestoremember').document('default').collection('Dates_to_Remember').snapshots();
  Stream stream2 = Firestore.instance.collection('datestoremember').document('Ngrx54m84JbsL0tGvrBeKCBlEnm2').collection('Dates_to_Remember').snapshots();

  return StreamGroup.merge([stream1, stream2]).asBroadcastStream();
}

EDIT using StreamZip:

Stream<List<QuerySnapshot>> getData() {
  Stream stream1 = Firestore.instance.collection('datestoremember').document('default').collection('Dates_to_Remember').snapshots();
  Stream stream2 = Firestore.instance.collection('datestoremember').document('Ngrx54m84JbsL0tGvrBeKCBlEnm2').collection('Dates_to_Remember').snapshots();
  return StreamZip<List<QuerySnapshot>>([stream1, stream2]);
}

And in StreamBuilder:

child: StreamBuilder(
        stream: getData(),
        builder: (BuildContext context, AsyncSnapshot<List<QuerySnapshot>> snapshot) {

          List<QuerySnapshot> combinedSnapshot = snapshot.data.toList();
          combinedSnapshot[0].documents.addAll(combinedSnapshot[1].documents);

          if(!combinedSnapshot[0].hasData) return const Text("Loading...");
          return new PageView.builder(
            itemCount: combinedSnapshot[0].data.documents.length,
            controller: PageController(viewportFraction: 0.5),
            onPageChanged: (int index) => setState(() => _index = index),
            itemBuilder: (_, i) {
              return Transform.scale(
                scale: i == _index ? 1 : 0.5,
                child: Card(
                  elevation: 6,
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(10)),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(combinedSnapshot[0].data.documents[i]['Date'].toDate().day.toString()),
                      Text(DateFormat.MMMM()
                          .format(
                          formatter.parse(combinedSnapshot[0].data.documents[i]['Date'].toDate().toString()))
                          .toString()),
                      Padding(
                        padding: const EdgeInsets.only(
                            left: 8.0, right: 8.0),
                        child: FittedBox(
                          fit: BoxFit.contain,
                          child: Text(
                            combinedSnapshot[0].data.documents[i]['Title'],
                            overflow: TextOverflow.ellipsis,
                          ),
                        ),
                      )
                    ],
                  ),
                ),
              );
            },
          );},
      ),
Share:
529
TJMitch95
Author by

TJMitch95

Updated on December 23, 2022

Comments

  • TJMitch95
    TJMitch95 over 1 year

    I am trying to combine two firestore streams in my Flutter application. However when I try and implement the merged stream I get the following error:

        The following NoSuchMethodError was thrown building StreamBuilder<dynamic>(dirty, state: _StreamBuilderBaseState<dynamic, AsyncSnapshot<dynamic>>#25b40):
    Class 'List<dynamic>' has no instance getter 'documents'.
    Receiver: _List len:2
    Tried calling: documents
    

    I assume there is another step I need to implement when I am establishing my stream before I can use it in a Pageview builder? Here are my streams:

    Stream<QuerySnapshot> getDefaultOccasions(BuildContext context) async*{
      yield* Firestore.instance.collection('datestoremember').document('default').collection('Dates_to_Remember').snapshots();
    }
    
    Stream<QuerySnapshot> getPersonalOccasions(BuildContext context) async*{
      final uid = await Provider.of(context).auth.getCurrentUID();
      yield* Firestore.instance.collection('datestoremember').document(uid).collection('Dates_to_Remember').snapshots();
    }
    
     getData() {
      Stream stream1 = Firestore.instance.collection('datestoremember').document('default').collection('Dates_to_Remember').snapshots();
      Stream stream2 = Firestore.instance.collection('datestoremember').document('Ngrx54m84JbsL0tGvrBeKCBlEnm2').collection('Dates_to_Remember').snapshots();
      return StreamZip([stream1, stream2]);
    }
    

    I then go and implement this here:

                  child: StreamBuilder(
                stream: getData(),
                builder: (context, snapshot) {
                  if(!snapshot.hasData) return const Text("Loading...");
                  return new PageView.builder(
                    itemCount: snapshot.data.documents.length,
                    controller: PageController(viewportFraction: 0.5),
                    onPageChanged: (int index) => setState(() => _index = index),
                    itemBuilder: (_, i) {
                      return Transform.scale(
                        scale: i == _index ? 1 : 0.5,
                        child: Card(
                          elevation: 6,
                          shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(10)),
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              Text(snapshot.data.documents[i]['Date'].toDate().day.toString()),
                              Text(DateFormat.MMMM()
                                  .format(
                                  formatter.parse(snapshot.data.documents[i]['Date'].toDate().toString()))
                                  .toString()),
                              Padding(
                                padding: const EdgeInsets.only(
                                    left: 8.0, right: 8.0),
                                child: FittedBox(
                                  fit: BoxFit.contain,
                                  child: Text(
                                    snapshot.data.documents[i]['Title'],
                                    overflow: TextOverflow.ellipsis,
                                  ),
                                ),
                              )
                            ],
                          ),
                        ),
                      );
                    },
                  );},
              ),
    

    Any ideas? Cheers

  • TJMitch95
    TJMitch95 over 3 years
    Thanks Ruben, this has taken away my errors but the merged only seems to display one of the original streams at a time, not combined like I was hoping. Any ideas how to get around this?
  • Ruben Röhner
    Ruben Röhner over 3 years
    Then I would suggest to use StreamZip like you did before and try to Cast this StreamZip. I updated my answer.
  • TJMitch95
    TJMitch95 over 3 years
    Thank you, i've implemented the changes but I am now faced with a new error: type '_MapStream<QuerySnapshotPlatform, QuerySnapshot>' is not a subtype of type 'Stream<Stream<QuerySnapshot>>', any thoughts?
  • Ruben Röhner
    Ruben Röhner over 3 years
    Maybe replace Stream<QuerySnapshot>> with only QuerySnapshot in your Cast
  • TJMitch95
    TJMitch95 over 3 years
    This takes me back to my original error: Class 'List<QuerySnapshot>' has no instance getter 'documents'. Receiver: _List len:2 Tried calling: documents -- Appreciate your suggestions though
  • Ruben Röhner
    Ruben Röhner over 3 years
    Ohh okay now I got it. Your StreamZip gives you a Stream that contains a List of QuerySnapshot. The first entry of this List is the QuerySnapshot of your stream1 and the second is the QuerySnapshot of your stream2.
  • TJMitch95
    TJMitch95 over 3 years
    Ok this makes sense, I can access individual streams by indexing but I need to combine both streams into one data stream (removing the need to index), how best to achieve this?
  • TJMitch95
    TJMitch95 over 3 years
    Thanks Ruben, I think there needs to be a couple of tweaks as i'm getting a couple of errors, the first: The operator '[]' isn't defined for the type 'AsyncSnapshot<dynamic>' when combining snapshots (specifically the index part) and the second: The getter 'data' isn't defined for the type 'QuerySnapshot'. when accessing combinedSnapshot.data.documents.length
  • Ruben Röhner
    Ruben Röhner over 3 years
    I have updated the getData() function and the builder inside StreamBuilder.
  • TJMitch95
    TJMitch95 over 3 years
    and now I am getting: The argument type 'Widget Function(BuildContext, List<QuerySnapshot>)' can't be assigned to the parameter type 'Widget Function(BuildContext, AsyncSnapshot<dynamic>)'
  • Ruben Röhner
    Ruben Röhner over 3 years
    I updated the StreamBuilder again. Now it should work.
  • TJMitch95
    TJMitch95 over 3 years
    Afraid not, here is the new error: type '_MapStream<QuerySnapshotPlatform, QuerySnapshot>' is not a subtype of type 'Stream<List<QuerySnapshot>>' -- maybe I should rethink my approach
  • Ruben Röhner
    Ruben Röhner over 3 years
    You can try adding a return-type to your getData() function like I did in my answer
  • TJMitch95
    TJMitch95 over 3 years
    I'm not sure what sort of return type I should be adding, any suggestions?