Backbone.js:更改没有射击model.change()

我正在面对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事件。 但是,我没有“富”日志在我的控制台…

我对骨干很新,而且还遇到同样的问题。

在做了一些研究之后,我发现了一些关于为什么发生这种情况的文章,并且最终发现了一些事情:

问题1

问题2

核心原因与引用平等与集合/成员平等的概念有关。 看来,在很大程度上,参考平等是骨干用来确定属性何时发生变化的主要技术之一。

我发现,如果我使用生成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]。

虽然我上面改进的代码触发了更改事件,但以下内容不是因为我的数组包含嵌套对象:

 var labelArray = _.clone(this.model.get("labels")); _.each(labelArray, function (label) { label.isSelected = (_.isEqual(label, selectedLabel)); }); this.model.set({ "labels": labelArray }); 

现在为什么这很重要? 经过非常仔细的debugging,我注意到在我的迭代器中,我引用的是存储相同的对象引用主干。 换句话说,我已经无意中进入了我的模型的内部,翻了一下。 当我调用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 }); 

有趣。 我会以为.set({cas:someArray})会引发更改事件。 就像你说的,似乎没有,我不能用.change()开火。但是,如果我只是做model.trigger('change')model.trigger('change:attribute')

这将允许您在没有随机属性的情况下触发更改事件。

如果有人可以解释事件,骨干和这个代码是怎么回事,那也能帮助我学习一些东西…这是一些代码。

 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 

我觉得这很有趣,我希望这个答案也会在我没有的评论中产生一些有见地的解释。