The situation explained
Here's the order the code runs:
- the model is created,
- model's
initialize
function is called, setting the loading
attribute to false
,
- then the model is passed to the view,
- then a listener is registered for the
"change:loading"
The event handler is never called because the event never occurs after it was registered.
Quick fix
First remove the set from the model.
var PageModel = Backbone.Model.extend({
defaults: {
loading: null
}
});
Then, after creating the view, set the loading
attribute.
var pageModel = new PageModel();
var pageView = new PageView({ model: pageModel });
pageModel.set('loading', false); // now the event should trigger
Since the listener is now registered before the model's loading
attribute is changed, the event handler will be called.
Optimized solution
Use Backbone's best practices:
A view is an atomic component that should only care about itself and its sub-views.
While in your case, it wouldn't matter much that you use the el
property on the view, it still goes beyond the responsibilities of the view. Let the calling code deal with passing the element to use for this view.
var PageView = Backbone.View.extend({
initialize: function() {
this.model = new PageModel();
this.$loader = this.$('.loader');
this.listenTo(this.model, "change:loading", this.loader);
},
loader: function() {
this.$loader[this.model.get("loading")? 'fadeIn': 'fadeOut'](700);
},
render: function() {
this.loader();
return this;
}
});
Put the defaults where they belong.
var PageModel = Backbone.Model.extend({
defaults: {
loading: false
}
});
Here we choose the body
as the element to use for the view, using the el
option, and then call render
when ready.
$(function() {
var pageView = new PageView({ el: 'body' }).render();
});
The event won't be triggered by the listener right away, instead, we use the render
function to put the view in its default state. Then, any subsequent changes of the loading
attribute will trigger the callback.
I have listed the most useful answers I've written about Backbone on my profile page. You should take a look, it goes from the beginning to advanced and even provides some clever Backbone components that solves common problems (like detecting a click outside a view).