Reputation: 75
Good day!
Recently I have been into backbone/require, and getting to learn some really cool stuff. I am trying to learn what is the best practice for showing the loading bar/spinner when a backbone collection is being fetched. Here are some strategies that I found as being used, for triggering a fetch/syncing event on the collection:
Method 1: Override the backbone's sync method before the application starts, and trigger a 'syncing' event on that collection
Method 2: Override the backbone's fetch method before the application starts, and trigger a 'fetching' event on that collection
Method 3: When a collection is being defined, override the fetch() method and trigger an event 'fetching', so that any instance can be monitored for fetching
Method 4: Some people suggest using event aggregation so that when a view calls fetch() for a collection, that view triggers an event.
Here is my situation:
What would be the best mechanism to to show the loading bar, keeping strict MVC pattern intact?
Option 1: Should the views listen to a 'syncing' event on the collection? Problem: If other fetch(), save() is called, the loading bar might display
Option 2: Should the views listen for a 'fetch()' event on the collection and act accordingly?
Option 3: Should one view inform another when it calls fetch() on a collection?
Option 4: Should the view call a fetching method on the window or an event aggregator?
Other Methods and Options are also welcomed. Your suggestions and advice would be the best resource. Thanks.
Upvotes: 0
Views: 1243
Reputation: 5263
In a context of Backbone.View, as an example:
initialize: function() {
this.state_loading();
// assuming this.collection is your collection which is not fetched yet...
this.collection.bind('reset', this.state_loaded, this);
this.collection.fetch();
},
state_loading: function() {
this.el.addClass('st-loading');
},
state_loaded: function() {
this.el.removeClass('st-loading');
}
Now class .st-loading
on the View element will simply display a spinner wherever you need, e.g.
.ajax-spinner { backgrund: url('...'); display: none; }
.st-loading .ajax-spinner { display: block; }
Now thoughts about your options:
Method 1: Don't override libraries. Next guy working on your code in production will curse you for that.
Method 2: You are better off triggering custom events on collection, you don't need to override any native Backbone methods. Again, this type of hacking is done only when you can't come up with good solutions.
Method 3: I guess your idea is that EVERY time something is loading you want to show a spinner? I would feel sorry for your users.
Method 4: If this is happening inside one view, you don't need to use event hubs. In the end, you can trigger custom event on a collection, and parent widget can subscribe to it. Another consideration is that you would most likely need to show spinner in different types of elements, and you would need to pass reference or selector for them for different views. Now if you want to have a universal solution, of course you can give your spinners same class application wide, but then you'll have a hell of headache if one day you want to remove them. You're definitely better off keeping these things localized to your views.
We have similar situation in a large app which is Backbone-driven. And for this purpose we have an extension which we apply to views that need to display a spinner. It looks somewhat like this:
var state_loading: function() {
if (arguments.length === 0 || arguments[0] === true) {
this.el.addClass('st-loading');
} else {
this.el.removeClass('st-loading');
}
}
var SomeView = Backbone.View.extend({
initialize: function(options) {
this.options = _.extend({}, this.options || {}, options || {});
this.collection = this.options.collection;
this.collection.bind('reset', this.render, this);
this.state_loading(true);
this.collection.fetch();
},
render: function() {
this.state_loading(false);
// your code...
}
});
_.extend(SomeView.prototype, state_loading);
Upvotes: 3