How to use Flutter (web app) stream builder with Firestore

1,624

Solution 1

I had the same issue when I tried to create a web version of my flutter mobile app which uses a lot of StreamBuilders. The following works for me:

Pubspec.yaml dependencies:

  firebase_web: ^5.0.9
  firebase_core: ^0.4.3+2

In your code:

import 'package:firebase_web/firestore.dart';
import 'package:firebase_web/firebase.dart';

body: new StreamBuilder(
  stream: firestore().collection('collection').onSnapshot,
  builder: (context, snapshot) {
...

Below I have included a list with changes that I encountered so far going from a flutter mobile app to a flutter web app:

  • documents = docs as in snapshot.data.docs.length
  • documents() = doc() as in firestore().collection('foo').doc('bar')
  • reference = ref as in snapshot.ref
  • data = data() as in snapshot.data()
  • The method setData from Firestore = set
  • The method updateData from Firestore = update(data:{'yourKey': 'yourValue',})

Hope this can help!

Solution 2

The querySnapshot.docs property returns a List<DocumentSnapshot>, while you need a stream for the stream property where each item on the stream is a list.

I've only needed this with the FlutterFire libraries for iOS/Android, but it should look something like this:

Stream<List<DocumentSnapshot>> getStream() async* {
  fb.firestore().collection("MyCollection").onSnapshot.listen((querySnapshot) {
    yield querySnapshot.docs;
  }
}
Share:
1,624
danh
Author by

danh

Updated on December 15, 2022

Comments

  • danh
    danh over 1 year

    I see several questions and answers about Flutter for mobile that use stream builder like this:

    body: new StreamBuilder(
      stream: Firestore.instance.collection("collection").snapshots(),
      builder: (context, snapshot) {
        ...
    

    I'm trying to do the same on flutter for the web, but in my configuration, the snapshots() method is unknown, generating an exception while running (and a vscode warning beforehand). Why? Do I have an incorrect setup?

    I've followed these steps which I found here and elsewhere:

    1) Included firebase as a dependency in pubspec.yaml

    dependencies:
      flutter:
        sdk: flutter
      firebase: ^6.0.0
    

    2) Included the firestore js scripts in the index.html body tag:

    <script src="https://www.gstatic.com/firebasejs/7.5.0/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.5.0/firebase-analytics.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.5.0/firebase-firestore.js"></script>
    <script src="main.dart.js" type="application/javascript"></script>
    

    3) In main.dart, imported firebase.dart files (using advice given here, though I'm not exactly sure which step above got me access to this package. I'm a flutter nube, if it isn't obvious)

    import 'package:flutter/material.dart';
    import 'package:firebase/firebase.dart' as fb;
    import 'package:firebase/firestore.dart' as fs;
    

    Having followed these steps, I can get this code working....

    void main() {
      if (fb.apps.length == 0) {
        try {
          fb.initializeApp(
            apiKey: "mike",
            authDomain: "myauthdomain",
            databaseURL: "mydburl",
            projectId: "myproductid",
            storageBucket: "mystoragebucket",
          );
        } catch(e) {
          print(e);
        }
      }
    
      fs.Firestore store = fb.firestore();
      fs.CollectionReference ref = store.collection("MyCollection");
      ref.onSnapshot.listen((querySnapshot) {
        querySnapshot.docs.forEach((doc) {
          print(doc.data());  // this works!!
        });
      });
      runApp(MyApp());
    }
    

    But, as I mentioned earlier, getting the stream builder working, all of the advice suggests that I can get a stream of snapshots by saying...

    class MyList extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new StreamBuilder(
          stream: fb.firestore().collection('MyCollection').snapshots(),
          ...
    

    The packages I have running on web don't seem to have anything like the snapshots method (or property) on a firestore collection reference. Can somebody set me straight?

  • danh
    danh over 4 years
    Thanks. Can you think of a reason why I'm seeing "Error: 'yield' isn't a type." on yield querySnapshot.docs();?
  • Frank van Puffelen
    Frank van Puffelen over 4 years
    Hmmm.... I was hoping this would work for you, as I use it in some of my own tests here: stackoverflow.com/a/59097364/209103
  • danh
    danh over 4 years
    I haven't actually tried this to see if it works, and I may not try it. I decided to abandon flutter for www until google actually (really) supports it. In the meantime, let's assume this works, and thanks.
  • Chris
    Chris about 4 years
    @Lorence, I can't get your method to work... what am I doing wrong? I know how to do this with Firestore in regular flutter, I can't understand what I need to do
  • Chris
    Chris about 4 years
    I want to use a Streambuilder to return a ListView.builder that return a list of widgets based on snapshot of documents in a collection...
  • Lorence Cramwinckel
    Lorence Cramwinckel about 4 years
    Hi @Chris if I understand correctly you want a streambuilder that returns a ListView.builder which returns widgets based on the snapshot. I put an example on github Check the code out here. Let me know if this is getting close to what you're looking for
  • Chris
    Chris about 4 years
    Hi Lorence, yes this is exactly what I'm trying to do. I understand the structure but the stream just isn't returning any data, or if it is it's not waiting for that data before the widget is built... So what I am getting is: "Something is wrong" .. no matter how I try to query, e.g. if(snapshot.hasData){} or whether I target a collection or document...
  • Chris
    Chris about 4 years
    Feel like I'm going mad... :(
  • Lorence Cramwinckel
    Lorence Cramwinckel about 4 years
    hm that is maddening indeed! What about your database rules? Do you have something like the following: match /databases/{database}/documents { match /{document=**} { allow read, write: if true; } Or what about your indexes?
  • Chris
    Chris about 4 years
    Omg.. I just switched it to true from false and now it's working... Thank you so much, I completely forgot about the database rules
  • Chris
    Chris about 4 years
    Hi again, I don't suppose you could help? I am able to target data by using a document as my stream but when using a collection I am unable to target info using the index... e.g. stream: Firestore.instance.collection('collection').snapshots() but when I try to do snapshot.data, I am unable to add .documents or .docs, and when I try snapshot.data[index]['data'] I am not getting anything back... Also, I'm having problems with itemCount because I am getting a Future<int> back :(
  • Lorence Cramwinckel
    Lorence Cramwinckel about 4 years
    have you tried using .onSnapshot instead of .snapshots(), so without the brackets?
  • CiriousJoker
    CiriousJoker over 3 years
    This should work: Stream<...> stream = fb.firestore().collection("MyCollection").onSnapshot; await for (final snapshot in stream) { yield* snapshot.docs; } }