2012-03-28 5 views
34

Я столкнулся с «изменить событие не обжиг» вопрос о Backbone.js =/Backbone.js: меняются не обстреле model.change()

Вот мой взгляд на модели пользователя:

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'); 

     } 

    }); 

Здесь, модель User:

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); 

      } 
     } 
    }); 

В модели пользователя, есть "саз" атрибут, который представляет собой массив объектов.

Я читал в других разделах, которые меняют события, это не огонь на model.set, если атрибуты не являются значением.

Итак, я пытаюсь вызвать событие изменения с помощью метода model.change(). Но у меня нет журнала «foo» в моей консоли ...

+0

На данный момент я решил эту проблему, добавив атрибут «rand» в свою модель. Я установил его в новое значение, когда хочу запустить событие change =/ – Atyz

+0

Хе-хе. Временное решение звучит немного взломанно. :-) Если ваш атрибут cas действительно является атрибутом модели пользователя, изменение этого путем выполнения 'User.set ({cas: [array]}) должно запускать событие изменения, которое я думаю. Он по-прежнему взломан, но вы всегда можете использовать 'model.change()' для ручного запуска изменения и изменения: событие атрибута. Вы не передаете '{silent: true}' где угодно? Можем ли мы увидеть ваш код модели пользователя? – jmk2142

+0

Hi Orangewarp, thx для вашего ответа :) Я добавляю модель User на сообщение, это очень просто. Как говорят другие ppl, магистраль не вызывает событие изменения, если атрибут не является значением. И я уже пытаюсь запустить вручную model.change(), он не работает, как я сказал ^^ – Atyz

ответ

67

Я довольно новичок в позвоночнике, и у меня была такая же проблема.

После выполнения некоторых исследований, я нашел несколько постов, которые проливают немного больше света на то, почему это происходит, и в конце концов все начали делать смысл:

Question 1

Question 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

подтягивание и синтаксический анализ - аккуратный! – Dmitry

+0

Большое вам спасибо, я только прочитал первые несколько предложений, но это сразу помогло мне, приветствует. –

+0

Даже с JSON.parse (JSON.stringify Я обнаружил, что массивы не всегда вызывают обновление.Я обычно .reverse() массив, а затем сортировать его с другой стороны, если порядок важен. –

14

Интересно. Я бы подумал, что .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 

Я нахожу это интересным, и я надеюсь, что этот ответ будет также появляться некоторые проницательные объяснения в комментариях, которые я не имею.

+0

Какую версию основы/подчеркивания вы используете? Ваш образец кода запускает изменения для меня в отладчике Chrome с BB 0.9.2 и _ 1.3.2: '> myShip = new Ship();' '> myShip.set ('cas', new Array()); ' '> myShip.set ({cas: [1,2,3]}); ' ' cas changed' 'general change' '> myArray = new Array(); ' '> myArray. push (4,5,6); ' '> myShip.set ({cas: myArray}); ' ' cas changed' 'general change' – radicand

+1

С теми же версиями BB & _, как orangewarp, события также срабатывают , Но в другом коде у меня такая же проблема, установка массива не возбуждает событие .... поиск причины ... – Kalamarico

+0

+1 это лучшее решение, чем принятый ответ. Я надеялся, что смогу инициировать событие изменения сам, но не знал, как это сделать. Я собирался создать фиктивный скалярный атрибут, чтобы инициировать изменения, но затем прокручивался до этого ответа. Благодаря! – Brandon