0

I have a collection that I'm listening to all model change events on. In one specific model property, I need to set an additional value on the model, which causes the event to be fired again. I'm trying to pass in custom options so I can ignore the second call. I don't want to use { silent: true } because I need the UI to update still.

The problem is my custom options are making it through. I have found the reason is because the change event is being fired within the change event on the current model, so it just continues it in the backbone code, and my custom options aren't being passed in.

This is what I'm doing. This is rough code for example purposes and not exact.

var View = Backbone.View.extend({
    initialize: function(){
        this.collection = new Backbone.Collection();
        this.listenTo(this.collection, "change", this._modelChange);
    },

    _modelChange: function(model, options)
    {
        if(!_.has(model.changed, "IsSelected")){
            model.set({ Selected: true }, { modelChanging: true });
        }

        // Do some other things...
    }
});

What's happening here is that I need to subscribe to any change event that happens and do something when it does. There are 10+ properties so I don't want to list them all. If the property that changed isn't IsSelected, the I need to set it to true. This will cause the change event to fire again, and the _modelChange method will be called again. This is where I'm expecting my { modelChanging: true } option to be available, but it isn't. I've found that this is happening because it's setting the value of the model during a change event, so backbone will fire the event itself, and backbone doesn't know about my options that I passed in.

This is one solution I've come up with, but I really don't like it.

setTimeout(function(){
    model.set({ Selected: true }, { modelChanging: true });
}, 0);

This will run it asynchronously so it will no longer be a part of the same event. I really don't like this and it feels like a major hack.

How can I accomplish this without a setTimeout?

Josh Close
  • 22,935
  • 13
  • 92
  • 140
  • this might be just as hacky as the setTimeout, but could you put `this.stopListening(this.collection, "change")` just before the conidtional in _modelChange, and then `this.listenTo(this.collection, "change", this._modelChange)` just after it? – Kyle R Feb 19 '14 at 00:06
  • I may have missed something, but it seems to work as expected http://jsfiddle.net/nikoshr/aPaF4/ – nikoshr Feb 19 '14 at 08:39
  • @nikoshr Yes, a simple fiddle worked for me too, so I'm not sure what it is that is causing it to get into this scenario. What is happening is here in the source. https://github.com/jashkenas/backbone/blob/master/backbone.js#L361 It goes into that while loop in the recursive call, and the event is triggered there, and my options aren't passed through then, just the original options. – Josh Close Feb 19 '14 at 14:46

0 Answers0