Reputation: 15642
Is there any sort of hooks in backbone where I can easily say "whenever any of the collections is fetching data, show the spinner, hide it when they're done"?
I have a feeling it will be more complicated than that and require overwriting specific functions. When should I show the spinner? On fetch()
or refresh()
or something else?
Upvotes: 24
Views: 16864
Reputation: 3403
I have used NProgress in my backbone and it is the best functioning loader/spinner out there.
var view = Backbone.View.extend({
initialize: function () {
this.items = new APP.Collections.itemCollection();
this.items.on('reset', this.myAddFunction, this);
NProgress.start();
collection.fetch({
reset:true,
success: function () {
NProgress.done(true);
}
});
}
});
Upvotes: 1
Reputation: 668
Use Backbone sync method, It will call every time backbone sync method, not only fetch, save, update and delete also
/* over riding of sync application every request come hear except direct ajax */
Backbone._sync = Backbone.sync;
Backbone.sync = function(method, model, options) {
// Clone the all options
var params = _.clone(options);
params.success = function(model) {
// Write code to hide the loading symbol
//$("#loading").hide();
if (options.success)
options.success(model);
};
params.failure = function(model) {
// Write code to hide the loading symbol
//$("#loading").hide();
if (options.failure)
options.failure(model);
};
params.error = function(xhr, errText) {
// Write code to hide the loading symbol
//$("#loading").hide();
if (options.error)
options.error(xhr, errText);
};
// Write code to show the loading symbol
//$("#loading").show();
Backbone._sync(method, model, params);
};
Upvotes: 0
Reputation: 1051
And a little update. Since Dec. 13, 2012 have been added a "request"
event to Backbone.sync, which triggers whenever a request begins to be made to the server. As well since Jan. 30, 2012 have been added a "sync"
event, which triggers whenever a model's state has been successfully synced with the server (create, save, destroy).
So, you don't need to override or extand the native Backbone's methodes. For listening 'start/finish fetching' event you can add listener to your model/collection like this for example:
var view = new Backbone.View.extend({
initialize: function() {
this.listenTo(this.model, 'request', this.yourCallback); //start fetching
this.listenTo(this.model, 'sync', this.yourCallback); //finish fetching
}
});
Upvotes: 3
Reputation: 6071
in Backbone.js 1.0.0 you can use the request
and sync
events http://backbonejs.org/#Events-catalog
This goes in the view.
initialize: function(){
this.items = new APP.Collections.itemCollection();
this.items.bind('request', this.ajaxStart, this);
this.items.bind('sync', this.ajaxComplete, this);
}
ajaxStart: function(arg1,arg2,arg3){
//start spinner
$('#item-loading').fadeIn({duration:100});
},
ajaxComplete: function(){
$('#item-loading').fadeOut({duration:100});
}
This can be applied per collection or per model here's some CSS for the spinner http://abandon.ie/notebook/simple-loading-spinner-for-backbonejs
Upvotes: 25
Reputation: 3767
The way i have done this without overriding backbone is:
In view
var myView = Backbone.View.extend({
initialize; function(){
this.$el.addClass('loading');
collection.fetch(success:function(){
this.$el.removeClass('loading')
})
}
})
The other route would be to remove the loading class when the models are added, usually you have:
var myView = Backbone.View.extend({
initialize; function(){
_.bindAll(this, 'addAll')
collection.bind('reset', this.addAll)
this.$el.addClass('loading');
collection.fetch();
},
addAll: function(){
this.$el.removeClass('loading');
collection.each(this.addOne);
}
})
These would be almost identical in most cases, and as the loader is really for the users experience removing it just prior to displaying the content makes sense.
Upvotes: 8
Reputation: 1680
You can use jQuery ajaxStart and ajaxStop. Those will globally run when an ajax request is made, so fetch and save will cause those to run. Add your code to show the spinner in the start and hide it in the end.
Upvotes: 37
Reputation: 11588
You can create a method called sync
on any of your models, and backbone.js will call that in order to sync. Or you can simply replace the method Backbone.sync.
This will allow you to make the change in only one place in your source code.
Upvotes: 1
Reputation: 2630
Backbone doesn't trigger any event when Collection::fetch()
starts (see source code), so you will have to override the fetch
method. Maybe something like this:
var oldCollectionFetch = Backbone.Collection.prototype.fetch;
Backbone.Collection.prototype.fetch = function(options) {
this.trigger("fetch:started");
oldCollectionFetch.call(this, options);
}
This will override the fetch
method to give you an event when the fetch starts. However, this only triggers the event on the specific collection instance so if you have a bunch of different collections you'll have to listen for that event on each collection.
Upvotes: 11