Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make Backbone.js Model change "partially" silent?

When my "chartModel" changes I want to update the "globalModel".

chartModel.bind("change", updateGlobalModel);

updateGlobalModel(){
  globalModel.set(obj)
}

And vice versa, I want my chartModel to update when the globalModel changes.

globalModel.bind("change", updateChartModel);

updateChartModel(){
  chartModel.set(obj)
}

This results in a feedback loop when setting the globalModel. I could prevent this by setting {silent:true}.

But here comes the problem. I have another Model that is dependent on the change event:

globalModel.bind("change", updateOtherModel);

How can I alert this model of the change but not the former one (to avoid the feedback loop)?

UPDATE:
For now, I decided to generate a specific ID for each set call:

set : function(attrs, options) { 
        if(!("setID" in attrs)){
            attrs.setID = myApp.utils.uniqueID(); //newDate.getTime();
        }
        Backbone.Model.prototype.set.call(this, attrs, options);
    },

This way, I can always generate a "setID" attribute from anywhere in my application. If the setID is still the same when fetching something from the model, I know there could be risk for a feedback loop.

like image 326
dani Avatar asked Dec 20 '11 20:12

dani


1 Answers

Better late than never..

The easiest way to do this is by using a flag. For example, when setting something in globalModel, you could also change a property on the model to indicate that you've changed something. You can then verify the value of this flag in updateChartModel. For example:

chartModel.bind("change", updateGlobalModel);

function updateGlobalModel() {
    if (!flag) {
        globalModel.set(obj);
        flag = true;
    }
}

Probably very similar to what you've ended up doing with your setID. As an aside, underscore has a uniqueId function built in.

Another thing that you can do, which is much cleaner, is to pass an option with your sets calls.

chartModel.set(obj, { notify : false });

Yes, you can pass any options you want, you're not just limited to { silent : true }. See this discussion on github for more. Then, you check for the existence of this property where you handle change events like so:

function updateGlobalModel(model, options){
    // explicitly check for false since it will otherwise be undefined and falsy
    // you could reverse it.. but I find this simpler
    if (options.notify !== false) {
        globalModel.set(obj)
    }
}

and in your third (and other models), you can just forego this check.

The final option is of course to look at your design. If these two models are so closely related that they must be kept in sync with each other, maybe it makes sense to merge their functionality. Alternatively, you could split the common functionality out. This all depends heavily on your particular situation.

like image 86
Radu Avatar answered Nov 06 '22 10:11

Radu