Pregunta

I'm using Firebase to store an array as part of a collection. When a user visits my webpage, I want to display the entire array's contents. I can retrieve this via the value event. Users on the page can also add elements to the array. This should also update the view.

I'm using Knockout.js to maintain the observable array which updates the display.

var Model = function (id) {
    var self = this;
    self.times = ko.observableArray();

    self.ref = firebase.child("users/" + id);

    self.ref.on("value", function (snapshot) {

        /* Logic to add each item to `times` goes here
         *
         * there is some logic that only needs to be performed
         * initially on the existing set of elements in the DB
         * such as sorting.  Ideally, this would not be done
         * for the `child_added` callback
         */

        self.ref.off("value");
        self.ref.on("child_added", self.addChild);
    });

    self.addChild = function (snapshot) {
        self.times.push(snapshot.val());
    }
};

However, this doesn't work as I expect since it seems like the second addChild is called from child_added even after value is fired. That is to say child_added retrieves all values even though value already has.

As an alternative I can use only value and just .removeAll before recreating the array, but this seems very wasteful.

No hay solución correcta

Otros consejos

This code uses this instead of self in one instance, which will cause unexpected errors.

Regarding arrays: Using an array to store data is not concurrency safe. When multiple users try to push to the same key, one will be overwritten. Instead, use an object and utilize Firebase's push command.

Regarding proper usage of child_added: The documentation for child_added states that there is no differentiation between existing and new records:

Child Added: This event will be triggered once for each initial child at this location, and it will be triggered again every time a new child is added. The DataSnapshot passed into the callback will reflect the data for the relevant child. For ordering purposes, it is passed a second argument which is a string containing the name of the previous sibling child by priority order (or null if it is the first child.)

The point here is to reduce code complexity. We're working in a real-time paradigm; data is in constant flux. There is no need to if/then/else around initial data vs new data vs posted data etc; it doesn't even make a lot of sense for real-time ops.

And finally, answering your question. As you can see from the points above, there is no need to use value in this case:

var Model = function (id) {
    var self = this;
    self.times = ko.observableArray();

    self.ref = firebase.child("users/" + id);

    // loads all data at this path, regardless of whether it existed
    // before or after I establish this listener
    self.ref.on("child_added", self.addChild.bind(self));

    self.addChild = function (snapshot) {
        self.times.push(snapshot.val());
    }
};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top