0

I'm coding an app for managing shift work. The idea is pretty simple: the team is shared between groups. In those groups are specific shifts. I want to get something like that:

Group 1
- shift11
- shift12
- shift13

Group 2
- shift21
- shift22
- shift23

I already made a couple of tests, but nothing is really working as I would like it to: everything reactive, and dynamic.

I'm using vue.js, firestore (and vuefire between them).

I created a collection "shiftGroup" with documents (with auto IDs) having fields "name" and "order" (to rearrange the display order) and another collection "shift" with documents (still auto IDs) having fields "name", "order" (again to rearrange the display order, inside the group) and "group" (the ID of the corresponding shiftGroup.)

I had also tried with firestore.References of shifts in groups, that's when I was the closest to my goal, but then I was stuck when trying to sort shifts inside groups.

Anyway, with vuefire, I can easily bind shiftGroup like this:

{
    data () {
        return {
            shiftGroup: [],    // to initialize
        }
    },
    firestore () {
        return {
            shiftGroup: db.collection('shiftGroup').orderBy('order'),
        }
    },
}

Then display the groups like this:

<ul>
    <li v-for="(group, idx) in shiftGroup" :key="idx">{{group.name}}</li>
</ul>

So now time to add the shifts... I thought I could get a reactive array of shifts for each of the groups, like that:

{
    db.collection('shift').where('group', '==', group.id).orderBy('order').onSnapshot((querySnapshot) => {
        this.shiftCollections[group.id] = [];
        querySnapshot.forEach((doc) => {
            this.shiftCollections[group.id].push(doc.data());
        });
    });
}

then I'd call the proper list like this:

<ul>
    <li v-for="(group, idx) in shiftGroup" :key="idx">
        {{group.name}}
        <ul>
            <li v-for="(shift, idx2) in shiftCollections[group.id]" :key="idx1+idx2">{{shift.name}}</li>
        </ul>
    </li>
</ul>

This is very bad code, and actually, the more I think about it, the more I think that it's just impossible to achieve. Of course I thought of using programmatic binding like explained in the official doc:

this.$bind('documents', documents.where('creator', '==', this.id)).then(

But the first argument has to be a string whereas I need to work with dynamic data.

If anyone could suggest me a way to obtain what I described.

Thank you all very much

Loki Faër
  • 169
  • 1
  • 4

1 Answers1

0

So I realize this is an old question, but it was in important use case for an app I am working on as well. That is, I would like to have an object with an arbitrary number of keys, each of which is bound to a Firestore document.

The solution I came up with is based off looking at the walkGet code in shared.ts. Basically, you use . notation when calling $bind. Each dot will reference a nested property. For example, binding to docs.123 will bind to docs['123']. So something along the lines of the following should work

export default {
    name: "component",
    data: function () {
        return {
            docs: {},
            indices: [],
        }
    },
    watch: {
        indices: function (value) {
            value.forEach(idx => this.$bind(`docs.${idx}`, db.doc(idx)))
        }
    }
}

In this example, the docs object has keys bound to Firestore documents and the reactivity works.

One issue that I'm trying to work through is whether you can also watch indices to get updates if any of the documents changes. Right now, I've observed that changes to the Firestore documents won't trigger a call to any watchers of indices. I presume this is related to Vue's reactivity, but I'm not sure.

tony19
  • 125,647
  • 18
  • 229
  • 307
santon
  • 4,395
  • 1
  • 24
  • 43