2

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
  • 62,181
  • 10
  • 95
  • 136

2 Answers2

4

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!

  • 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. – danh Jan 27 '20 at 15:32
  • @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 Feb 17 '20 at 00:44
  • 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... – Chris Feb 17 '20 at 00:45
  • 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](https://github.com/winckles/rooster/blob/master/chris). Let me know if this is getting close to what you're looking for – Lorence Cramwinckel Feb 17 '20 at 09:52
  • 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 Feb 17 '20 at 10:25
  • Feel like I'm going mad... :( – Chris Feb 17 '20 at 10:31
  • 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? – Lorence Cramwinckel Feb 17 '20 at 10:41
  • 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 Feb 17 '20 at 11:01
  • 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 back :( – Chris Feb 17 '20 at 12:27
  • have you tried using `.onSnapshot` instead of `.snapshots()`, so without the brackets? – Lorence Cramwinckel Feb 17 '20 at 13:54
1

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;
  }
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks. Can you think of a reason why I'm seeing "Error: 'yield' isn't a type." on `yield querySnapshot.docs();`? – danh Dec 02 '19 at 22:11
  • 1
    Hmmm.... I was hoping this would work for you, as I use it in some of my own tests here: https://stackoverflow.com/a/59097364/209103 – Frank van Puffelen Dec 02 '19 at 23:28
  • This should work: Stream<...> stream = fb.firestore().collection("MyCollection").onSnapshot; await for (final snapshot in stream) { yield* snapshot.docs; } } – CiriousJoker Sep 09 '20 at 19:53