可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Using backbone.js...
@model.bind 'change', ()-> console.log 'updated'
addIndex = (index) =>
array = @model.get('array')
array.push index
@model.set
array: array
This updates the model perfectly but doesn't trigger the change event. Does anyone know why from looking at what I posted?
EDIT:
I added this and it triggers the change event:
@model.set
test: ''
num = 0
setInterval ()=>
num++
@model.set
test: num
, 3000
I added this and it doesn't trigger the change event:
@model.set
test: []
num = 0
setInterval ()=>
console.log 'testupdate'
num++
test = @model.get('test')
test.push num
@model.set
test: test
, 3000
回答1:
Brian's answer as to the reason is awesome!
Wanted to present another way to get what you want instead of nulling it out or cloning the array.
Just manually trigger the change yourself:
addIndex = (index) =>
array = @model.get('array')
array.push index
@model.trigger('change:array',@model, array)
回答2:
Since you're setting the referenced object, use _.clone()
.
test = _.clone @model.get('test')
test.push num
@model.set test: test
Since you're no longer using the referenced object/array to set itself, it will fire the change event if it has changed.
回答3:
The problem is that you are setting the value with the existing value. Take a look at the source code:
http://documentcloud.github.com/backbone/docs/backbone.html#section-33
When you call set
it has a guard clause to make sure that you are not setting the same value (to avoid event loops). In your case, you are getting the array, modifying it, and setting it again, which will not trigger your event.
Of course, when you set test: {}
, it is a new item with a new object, so it will trigger again. If you really want to trigger the event, you can set it to null, then set it to an empty array and then to the populated array again...
回答4:
Another way to go, when changing objects or arrays, is to silently unset the property before setting the new updated value. Something like this:
(function() {
var arr, model = new Model();
model.set( "arrayProp", [1, 2, 3] );
arr = model.get( "arrayProp" );
arr.push( 4 );
model.unset( "arrayProp", { silent: true } );
model.set( "arrayProp", arr );
})();
By setting silent: true
when unsetting the prop, the change event will only fire once (When the set()
method is called and the property has been updated).
There isn't really a difference between doing this or manually calling the event, it's just a matter of personal preference.
回答5:
Could you consider using a Backbone collection instead of an array, and then binding to change events in that collection?