Ravi Hamsa
Ravi Hamsa

Reputation: 4721

backbone model set and unset in same single method call

Assume I have one backbone model with state

var myModel = new Backbone.Model(
    {
        key1:'value1', 
        key2:'value2', 
        key3:'value3'
    });

myModel.on('all', function allHanlder () {
    console.log(arguments);
})

I need remove key1 and key2 and change key3. Possible options are

  1. unset key1 and key2 , set key3 attribute
  2. clear model and set key3

option 1 results in 3 change, 3 change attribute events

myModel.unset('key1');
myModel.unset('key2');
myModel.set({key3:'newValue3'})

//events


["change:key1", Object { cid="c1355", attributes={...}, _changing=true, more...}, undefined, Object { unset=true}]
["change", Object { cid="c1355", attributes={...}, _changing=true, more...}, Object { unset=true}]
["change:key2", Object { cid="c1355", attributes={...}, _changing=true, more...}, undefined, Object { unset=true}]
["change", Object { cid="c1355", attributes={...}, _changing=true, more...}, Object { unset=true}]
["change:key3", Object { cid="c1355", attributes={...}, _changing=true, more...}, "newValue3", Object {}]
["change", Object { cid="c1355", attributes={...}, _changing=true, more...}, Object {}]

option 2 will result in 2 change change:attribute events

myModel.clear()
myModel.set({key3:'newValue3'})

//output


["change:key1", Object { cid="c1356", attributes={...}, _changing=true, more...}, undefined, Object { unset=true}]
["change:key2", Object { cid="c1356", attributes={...}, _changing=true, more...}, undefined, Object { unset=true}]
["change:key3", Object { cid="c1356", attributes={...}, _changing=true, more...}, undefined, Object { unset=true}]
["change", Object { cid="c1356", attributes={...}, _changing=true, more...}, Object { unset=true}]
["change:key3", Object { cid="c1356", attributes={...}, _changing=true, more...}, "newValue3", Object {}]
["change", Object { cid="c1356", attributes={...}, _changing=true, more...}, Object {}]

change:attribute events are fair, but I need to minimise change triggers. Something like below.

myModel.someMagicSet({key3:'newValue3'})

//output

["change:key1", Object { cid="c1355", attributes={...}, _changing=true, more...}, undefined, Object {}]
["change:key2", Object { cid="c1355", attributes={...}, _changing=true, more...}, undefined, Object {}]
["change:key3", Object { cid="c1355", attributes={...}, _changing=true, more...}, "newValue3", Object {}]
["change", Object { cid="c1355", attributes={...}, _changing=true, more...}, Object {}]

Is there is a way I can achieve it without overriding backbone behaviours?

Upvotes: 1

Views: 447

Answers (1)

RustyToms
RustyToms

Reputation: 7810

myModel.unset('key1', {silent: true});
myModel.unset('key2', {silent: true});
myModel.set({key3:'newValue3'}, {removed: ['key1', 'key2']});

This will do what you want while only triggering one change event. You are passing in the removed items to your handler in the options object. In your handler, your code should look like this:

myModel.on('all', function allHandler (model, options) {
    console.log(options.removed);  // this should show you what has been removed before
    // other code
})

Alternately, you could pass a flag in your options with each event which you could analyze in your handler, which would determine whether the handler was run or not. This would give your handler access to what has been changed, but it would have to store it outside of it's own scope in order to access it the next time.

myModel.unset('key1', {finished: false});
myModel.unset('key2', {finished: false});
myModel.set({key3:'newValue3'}, {finished: true});

EDIT: Here is a one liner that should do everything:

myModel.clear({reset: {key3: 'newValue3'}});

and then in your handler do this

myModel.on('all', function allHandler (model, options) {
  if (options.reset){        
    model.set(options.reset);
  }
    // other code
})

The thing you should watch out for is that clear removes the id too, so if you need that you should pass it in with your options:

myModel.clear({reset: {key3: 'newValue3', id: myModel.get('id')}});

Upvotes: 1

Related Questions