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

        }

    });

Здесь модель 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);

            }
        }
    });

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

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

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

 Atyz29 мар. 2012 г., 10:24
Привет Orangewarp, спасибо за ваш ответ :) Я добавляю модель User на пост, это очень просто. Как говорят другие люди, магистраль не запускает событие изменения, если атрибут не является значением. И я уже пытаюсь вручную вызвать model.change (), он не работает, как я сказал ^^
 Atyz28 мар. 2012 г., 17:00
На данный момент я решил эту проблему, добавив атрибут «rand» в мою модель. Я устанавливаю его на новое значение, когда хочу запустить событие change = /
 jmk214229 мар. 2012 г., 03:28
Хе хе Временное решение звучит немного глупо, хотя. :-) Если ваш атрибут cas действительно является атрибутом в модели User, измените его, выполнивUser.set({cas:[array]}) должен вызвать событие изменения, которое я думаю. Это все еще хакерский, но вы всегда можете использоватьmodel.change() вручную вызвать изменение и изменить: атрибут атрибута. Вы не проходите мимо{silent:true} ты где? Можем ли мы увидеть ваш код модели пользователя?

Ответы на вопрос(2)

Решение Вопроса

и у меня была такая же проблема.

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

Вопрос 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 });
});

ПРИМЕЧАНИЕ: в соответствии сПодчеркнуть 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 });
 Erico Chan10 июл. 2014 г., 18:01
с помощью_.extend({}, this.model.get("labels")) также может вернуть глубокую копию объекта
 Dmitry25 февр. 2013 г., 00:55
Стригирование и разбор - аккуратно!
 Josh Mc21 мар. 2014 г., 07:53
Большое спасибо, я прочитал только первые несколько предложений, но это мне сразу помогло, ура.
 Daniel Roizman01 июн. 2014 г., 05:36
Даже с JSON.parse (JSON.stringify я обнаружил, что массивы не всегда вызывают обновление. Я обычно .reverse () массив, а затем сортировать его на другой стороне, если порядок важен.

.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

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

 Brandon14 апр. 2013 г., 19:04
+1 это лучшее решение, чем принятый ответ. Я надеялся, что смогу инициировать событие изменения самостоятельно, но не знал как. Я собирался создать фиктивный скалярный атрибут, чтобы вызвать изменения, но затем прокрутил до этого ответа. Спасибо!
 tvshajeer04 февр. 2015 г., 06:03
@ orangewarp, как применить этот метод к значению текстового поля, это изменить. я должен использоватьthis.on('change:input.txtclass', this.notify, this); когда у меня есть несколько текстовых полей с тем же событием изменения<input type="text" class="txtclass"></input> <input type="text" class="txtclass"></input>
 Kalamarico24 мая 2012 г., 22:31
С такими же версиями BB & _ как orangewarp события тоже происходят. Но в другом коде у меня та же проблема, установка массива не запускает событие .... поиск причины ...
 radicand04 мая 2012 г., 16:10
Какую версию основы / подчеркивания вы используете? Ваш пример кода запускает изменения для меня в отладчике 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
 jmk214204 февр. 2015 г., 22:29
@tvshajeer Не совсем. Я думаю, что вы пытаетесь подключить DOM-события через jQuery, и вы смешиваете их с Backbone Events, которые в основном используются для запуска обработчиков на моделях и тому подобное. Входы не будут иметь Backbone.Events расширены и не будут реагировать на событие «изменения», я не думаю. В магистрали все, как правило, управляется данными ... так что ваш View будет устанавливать данные модели на основе вашего входного интерфейса, а затем ваш View будет прослушивать attr модели для события 'change', чтобы затем запускатьсяthis.notify, Кроме того, вы должны использовать более новый .listenTo, а не .on на этом этапе.

Ваш ответ на вопрос