Reputation: 97
Logic of my app is quite straightforward. I have Model that fetching JSONP (data contains years, quarter, and quarter contains different key:value). After fetching data, View listens for Model's "change" event and then rendering data. So far so good.
But then I need to listen for a "change:year"/"change:quarter" and fetch data with new url, based on changes. But when "change:year"/"change:quarter" fired, global "change" is fired also.
Sure, if I'll use Collection instead of Model – theres is "reset" for me. But in this case I can't listen for "change:year" so easily – I have to create few more Models (for year, quarter and each key in quarters). But I want to keep app simple.
Is there other way around? Or creating much more Model is inevitable?
Thanks.
UPD: "change" event still needed, because Model have to rerender, after fetching new data.
SOLUTION: I've created common Controller, that holds atributes, that needed to be changed. And in .url() method getting them from Controller to modify url. I stick to Collection's fetch()/"reset" notifying and made listener for Controller on "change". So, when I'm changing "year"/"quarter", View get notification from Controller, and when corresponding Collection fetching - it's fetching with new url.
Upvotes: 3
Views: 250
Reputation: 3120
You can check changed attributes in model's change listener.
var MyModel=Backbone.Model.extend({
initialize:function(){
this.bind("change",this.changeModel);
this.bind("change:year",this.changeYear);
},
changeModel:function(model,objs){
//Checking changed attributes
if (_.has(objs.changes,"year") || _.has(objs.changes,"quarter")) return this;
console.log("Processing",objs.changes);
return this;
},
changeYear:function(model,new_val){
console.log("year changed.",new_val);
return this;
}
});
var mymodel=new MyModel();
mymodel.set("year",2012);
mymodel.set("month",6);
If you have a view that listening model's change event, you should add a different attribute to the model and listen this attribute's change event instead of model's change event and render view when this attribute change. Change this attribute's value in changeModel function and fire listeners if your "year" and "quarter" attributes not in changed attributes as below.
//Edit changeModel as below
changeModel:function(model,objs){
//Checking changed attributes
if (_.has(objs.changes,"year") || _.has(objs.changes,"quarter")) return this;
this.set("rerender",!this.rerender); //Changing for triggering change event
return this;
},
//View's constructor function
initialize:function(){
this.model.bind("change:rerender",this.render);
}
Upvotes: 1
Reputation:
As I understand you, you don't want to receive the global model change
event if only year
or quarter
changed - but you have to.
So instead when getting the receiving the global change event, you can check if it was onlyyear
or quarter
that was changed, and the skip the normal event handling. Something like this:
this.model.bind("change", this.render, this);
this.model.bind("change:year", this.fetchSomething, this);
this.model.bind("change:quarter", this.fetchSomething, this);
render : function(){
var attributesExceptYearAndQuarter = _.without(this.model.attributes, ['year', 'quarter'])
if(this.model.changedAttributes(attributesExceptYearAndQuarter).length > 0){
// do the rendering
}
}
Upvotes: 1