knockoutFire
knockoutFire copied to clipboard
Best way to subscribe to individual changes in collection?
In Firebase I am storing a bunch of keys/ids, but no real data. For example I store user IDs, but not user names. So when it comes time to display the user, I make another request to another service to populate the rest of the item. To get this to work, I need to know which individual item has changed in the collection. My first attempt was something like this:
// init knockoutfire
self.suggestions2({ collection: KnockoutFire.observable(recommenderFirebase.child('ratings/suggestions').child(user.id), {
'.limit': 20,
"$suggestion" : {
accountID: true,
itemID: true,
relevance: true
}
})
});
// ******* TRYING TO SUBSCRIBE TO INDIVIDUAL ELEMENT CHANGES ********
self.suggestions2().collection.subscribe(function(newValue) {
log(newValue.length);
log(newValue[0]().itemID());
});
But this listens to the whole collection, returning all 20 items, instead of the individual item that was changed.
A horrible but functional way to solve this would be if I were willing to modify KnockoutFire itself, and populate the rest of the object on the native Firebase changes. So for example, KnockoutFire listens to "child_added" - if in that function I populated the object it would work (see bottom) :
firebaseRef.on("child_added", function(childSnap, prevChildName) {
//var child = KnockoutFire.observable(childSnap.ref(), map[childVariable]);
var childMap = map[childVariable];
var child = KnockoutFire.mapObservable(childMap);
if (childSnap.getPriority()) {
child()[".priority"] = childSnap.getPriority();
}
child.extend({firebaseObject: {firebaseRef: childSnap.ref(), map: childMap}});
//console.log(childSnap.ref().path.toString() + ":" + child().firebase);
self.insert(child, prevChildName, map[".reverse"]);
self().last(child());
// ******* POPULATE OBJECT ********
outsideService.populate(child());
});
Of course I don't want to do that. So whats's the best way to listen to changes to individual elements in the collection, and not the whole collection itself?
I'm not sure why I didn't think of this originally, but I can simply subscribe directly to the underlying Firebase independent of KnockoutFire:
recommenderFirebase.child('ratings/suggestions').child(user.id).limit(20).on('child_added', function(data) {
log(data.val());
});
I think ".extend" map option may work.
ko.extenders.suggestion = function(target) {
outsideService.populate(target());
};
then specify the extender.
"$suggestion" : {
".extend": {"suggestion": null},
...
}