Working well with the Backfire model, I have a few thoughts on this. I hope that some of them will give you good ideas for your project.
Real-time change in mental models
First of all, get out of the mindset, knowing when “all the data is loaded”, assuming that it bothers you, as before. We are now in real time. Just start from scratch and process every entry that comes as an update. This saves a lot of time and effort when trying to cope with conditions.
lazy rendering and DOM bindings
Now with Backbone, I often find that I want to do a lazy render. That is, I want to deal with the following conditions logically:
- start collecting data immediately, but don’t show it until the render is called
- a “download” message is displayed until some data appears.
- when multiple entries arrive close together, do not redraw for each individual
A good solution for frequently changing data is Backbone.ModelBinder A CollectionBinder tool that manages each node DOM separately, rendering all records. There are many examples on their site, so I won’t go into details here.
Failure as a quick and dirty solution
The Underscore debounce method is an excellent solution for small-sized DOM manipulations that do not need all the complexity of data bindings. Debounce with an expectation of about 250 works well for me, ensuring that rendering always happens when the data changes, but only once if we get a large number of updates per line.
Assuming we created a collection that extends Backbone.Firebase.Collection, then we can do something like the following:
var View = Backbone.View.extend({ initialize: function() { this.listenTo( this.collection, 'add remove', _.debounce(_.bind(this.dataChanged, this), 250) ); }, render: function() { this._isRendered = true; }, dataChanged: function() {
Using deferred wait to load data
In my Backfire implementation, I added a stateful method that notifies me of the first boot. I did this using the jQuery Deferred object. Then I just listen to the collection to fire the sync event:
this.collection.once('sync', );
The nice thing about Firebase is that the original results of Firebase.on ('child_added' ...) (existing entries) tend to come in one beautiful big chunk - one after another. Since the added bonus, I use debounce so that my “loaded” method starts after the initial compilation is completed, so I don’t get one record, the call is loaded, and then I need to immediately take some action for a series of updates.
Since this is a specific implementation, I am going to be a bit abstract here, but this is the gist:
// inside my wrapper for Backbone.Firebase.Collection this.ready = $.Deferred(); // debounce our ready listener so it fires on the tail end of // the initial update clump which reduces the number of update // calls on the initial load process considerably this.readyFn = _.debounce(this.ready.resolve, 250); // start monitoring for the first series of updates // this would need to be invoked before the sync is established this.on( 'add', this.readyFn ); // wait for the data to come in this.ready.always( _.bind(function() { // when the ready promise is fulfilled, we can turn off the listener this.off('add', this.readyFn); // this is where we trigger the listener event used above this.trigger('sync'); }, this) );
I will use this solution with caution. I find that in most cases I can greatly simplify the situation by forgetting about the initial loads and initializing everything empty, and then viewing everything as an update.
I use this only in cases where I need to show an alternative view if there is no data (for example, getting started instructions).