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().
Но у меня нет записи "foo" в моей консоли...
Ответы
Ответ 1
Я новичок в позвоночнике, и у меня была такая же проблема.
После некоторых исследований я нашел несколько сообщений, которые проливают немного больше света на то, почему это происходит, и в конечном итоге все стало иметь смысл:
Вопрос 1
Вопрос 2
Основная причина связана с понятием равенства ссылок и равенства set/member. Похоже, что в значительной степени ссылочное равенство является одним из основных методов, используемых основой, чтобы выяснить, когда изменился атрибут.
Я нахожу, что если я использую методы, которые генерируют новую ссылку, такую как 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 });
Теперь почему это имеет значение? После отладки очень осторожно, я заметил, что в моем итераторе я ссылался на тот же объект, что и опорная магистраль. Другими словами, я случайно потянулся к внутренности моей модели и слегка перевернулся. Когда я вызывал 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 });
Ответ 2
Интересно. Я бы подумал, что .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
Я нахожу это интересным, и я надеюсь, что этот ответ также породит некоторое проницательное объяснение в комментариях, которых у меня нет.