Darkade
Darkade

Reputation: 947

Using Document Reference Type with Flutter, Provider and Firestore

I'm using Provider, and Firestore to get some documents that are using the Document Reference Type in their data model

Is there a good way to get both the data and the nested references in the same "Widget building" pass?

I can retrieve the data, and I can build my classes and widgets from the data, but I'm not able to to update the widgets after I retrieve the referenced documents.

A data model for the object in question would look like this:

{
    name: "Check name",
    modifiers: [1, 2 ,3],
    stats: [stat_reference_one, stat_reference_two]
}

Where stat_reference_one is a path and the reference type. And it's path is: "/users/.../.../checks/:id"

In my data service I have the following code:

class DataService {
  final FirebaseFirestore _db = FirebaseFirestore.instance;

  Stream<List<Check>> getChecks() {
    var ref = _db.collection(
        "/users/.../.../checks/");

    return ref.snapshots().map((list) => list.docs.map((doc) {
          Map _a = doc.data() as Map<dynamic, dynamic>;

          var _alternatives = _a['rollAlternatives']['default'];

          List _s = _alternatives['stats'];

          List<Stat> SS = [];
          _s.forEach((e) => getStat(e.parent.path, e.id).listen((Stat event) {
                SS.add(event);
              }));

          return Check.fromFirestore(doc, statList: SS);
        }).toList());


  Stream<Stat> getStat(String parentPath, String docId) {
    return _db
    .collection(parentPath)
    .doc(docId)
    .get()
    .asStream()
    .map((doc) => Stat.fromFirestore(doc));
  }

There you can see I have two builders aStat.fromFirestore and a Check.fromFirestore

class Stat {

  ...

  Stat(this.name, this.value);

  ...

  factory Stat.fromFirestore(DocumentSnapshot doc) {
    Map data = doc.data() as Map<dynamic, dynamic>;
    return Stat(
      data['name'],
      data['value'],
    );
  }
}

So, the getChecks method consumes getStat and therefore Stat before trying to create a new Check object instance. But at the moment it creates the Check object the stream for Stat has not finished yet. So my widget is drawn with just the constant values from the modifiers field. And it's not until I change screen that I see the widget rendered with the result from the stats field, so it works, but it's not rendered "on time"

Is there a good way to solve for this? I could turn getStat into a future, but then I wouldn't get the data on stream, which is something I need.

Maybe there's a way to wait for the stream to solve and then return the result of getChecks I tried to use the onDone parameter of listen, but that that has a type signature of void.

Thank you in advance

Upvotes: 0

Views: 1345

Answers (1)

Yanni TheDeveloper
Yanni TheDeveloper

Reputation: 406

When working with more streams nested to each other, it's wise to use packages like RxDart. Which will ease and smooth your program. https://pub.dev/packages/rxdart

You should definately check out, according to your explanation switchLatest function would do the job for you. https://pub.dev/documentation/rxdart/latest/rx/Rx/switchLatest.html

Let me know if you got questions.

Upvotes: 1

Related Questions