我在Backbone.js = /
面临“更改事件未触发”问题这是我对用户模型的看法:
window.UserView = Backbone.View.extend({
...
initialize: function()
{
this.model.on('destroy', this.remove, this);
this.model.on('change', function()
{
console.log('foo');
});
},
render: function(selected)
{
var view = this.template(this.model.toJSON());
$(this.el).html(view);
return this;
},
transfer: function(e)
{
var cas = listofcas;
var transferTo = Users.getByCid('c1');
var transferToCas = transferTo.get('cas');
this.model.set('cas', cas);
console.log('current model');
console.log(this.model);
//this.model.change();
this.model.trigger("change:cas");
console.log('trigger change');
transferTo.set('cas', transferToCas);
console.log('transferto model');
console.log(transferTo);
//transferTo.change();
transferTo.trigger("change:cas");
console.log('trigger change');
}
});
这里是用户模型:
window.User = Backbone.Model.extend({
urlRoot: $('#pilote-manager-app').attr('data-src'),
initialize: function()
{
this.set('rand', 1);
this.set('specialite', this.get('sfGuardUser').specialite);
this.set('name', this.get('sfGuardUser').first_name + ' ' + this.get('sfGuardUser').last_name);
this.set('userid', this.get('sfGuardUser').id);
this.set('avatarsrc', this.get('sfGuardUser').avatarsrc);
this.set('cas', new Array());
if (undefined != this.get('sfGuardUser').SignalisationBouclePorteur) {
var cas = new Array();
_.each(this.get('sfGuardUser').SignalisationBouclePorteur, function(value)
{
cas.push(value.Signalisation);
});
this.set('cas', cas);
}
}
});
在用户模型中,有“cas”属性,它是一个对象数组。
我在其他主题中读到,如果属性不是值,则更改事件不会触发model.set。
因此,我尝试使用model.change()方法直接触发change事件。 但是,我的控制台中没有“foo”登录...
答案 0 :(得分:70)
我对骨干很新,我遇到了同样的问题。
在做了一些研究之后,我发现了一些帖子,它们更清楚地说明了为什么会这样,最终事情开始变得有意义了:
核心原因与参考平等与集合/成员平等的概念有关。似乎在很大程度上,引用相等性是主干用于确定属性何时发生变化的主要技术之一。
我发现如果我使用生成类似Array.slice()或_.clone()的新引用的技术,则会识别更改事件。
因此,例如,以下代码不会触发事件,因为我正在改变相同的数组引用:
this.collection.each(function (caseFileModel) {
var labelArray = caseFileModel.get("labels");
labelArray.push({ Key: 1, DisplayValue: messageData });
caseFileModel.set({ "labels": labelArray });
});
虽然此代码确实触发了事件:
this.collection.each(function (caseFileModel) {
var labelArray = _.clone(caseFileModel.get("labels")); // The clone() call ensures we get a new array reference - a requirement for the change event
labelArray.push({ Key: 1, DisplayValue: messageData });
caseFileModel.set({ "labels": labelArray });
});
注意:根据Underscore API,_. clone()通过引用复制某些嵌套项。虽然克隆了根/父对象,但它对于主干很好。也就是说,如果您的数组非常简单并且没有嵌套结构,例如[1,2,3]。
虽然上面改进的代码触发了change事件,但以下内容并没有因为我的数组包含嵌套对象:
var labelArray = _.clone(this.model.get("labels"));
_.each(labelArray, function (label) {
label.isSelected = (_.isEqual(label, selectedLabel));
});
this.model.set({ "labels": labelArray });
现在为什么这很重要?在仔细调试之后,我注意到在我的迭代器中我引用了相同的对象引用主干存储。换句话说,我无意中伸手进入了模型的内部并翻了一下。当我调用setLabels()时,骨干正确地认识到没有任何改变,因为它已经知道我翻了一下。
在浏览了一些之后,人们似乎普遍认为javascript中的深层复制操作真的很痛苦 - 没有任何内置的功能。所以我这样做了,这对我来说很好 - 一般适用性可能会有所不同:
var labelArray = JSON.parse(JSON.stringify(this.model.get("labels")));
_.each(labelArray, function (label) {
label.isSelected = (_.isEqual(label, selectedLabel));
});
this.model.set({ "labels": labelArray });
答案 1 :(得分:14)
有趣。我原以为.set({cas:someArray})
会引发一场变革事件。就像你说的那样,它似乎没有,我无法用.change()
来解决这个问题,但如果我只是做model.trigger('change')
或model.trigger('change:attribute')
我可以让事件发挥作用
这将允许您在没有随机属性黑客的情况下触发更改事件。
如果有人能解释事件,Backbone和这段代码的内容,那将有助于我学习一些东西......这是一些代码。
Ship = Backbone.Model.extend({
defaults: {
name:'titanic',
cas: new Array()
},
initialize: function() {
this.on('change:cas', this.notify, this);
this.on('change', this.notifyGeneral, this);
},
notify: function() {
console.log('cas changed');
},
notifyGeneral: function() {
console.log('general change');
}
});
myShip = new Ship();
myShip.set('cas',new Array());
// No event fired off
myShip.set({cas: [1,2,3]}); // <- Why? Compared to next "Why?", why does this work?
// cas changed
// general change
myArray = new Array();
myArray.push(4,5,6);
myShip.set({cas:myArray}); // <- Why?
// No event fired off
myShip.toJSON();
// Array[3] is definitely there
myShip.change();
// No event fired off
可能对你有帮助的有趣部分:
myShip.trigger('change');
// general change
myShip.trigger('change:cas');
// cas changed
我发现这很有趣,我希望这个答案也会在我没有的评论中产生一些有见地的解释。