Backbone.js:更改不在model.change()上触发

Aty*_*tyz 36 events backbone.js

我正面临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');

        }

    });
Run Code Online (Sandbox Code Playgroud)

在这里,用户模型:

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

            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

在用户模型中,有"cas"属性,它是一个对象数组.

我在其他主题中读到,如果属性不是值,则更改事件不会触发model.set.

所以,我尝试使用model.change()方法直接触发change事件.但是,我的控制台中没有"foo"日志...

kil*_*ush 71

我对骨干很新,我遇到了同样的问题.

在做了一些研究之后,我发现了一些帖子,它们更清楚地阐明了为什么会发生这种情况,最终事情开始变得有意义了:

问题1

问题2

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

我发现如果我使用生成类似Array.slice()或_.clone()的新引用的技术,则会识别change事件.

因此,例如,以下代码不会触发事件,因为我正在改变相同的数组引用:

this.collection.each(function (caseFileModel) {
    var labelArray = caseFileModel.get("labels");
    labelArray.push({ Key: 1, DisplayValue: messageData });
    caseFileModel.set({ "labels": labelArray });
});
Run Code Online (Sandbox Code Playgroud)

虽然此代码确实触发了事件:

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 });
});
Run Code Online (Sandbox Code Playgroud)

注意:根据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 });
Run Code Online (Sandbox Code Playgroud)

现在为什么这很重要?在仔细调试之后,我注意到在我的迭代器中我引用了相同的对象引用主干存储.换句话说,我无意中伸手进入了模型的内部并翻了一下.当我调用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 });
Run Code Online (Sandbox Code Playgroud)

  • 字符串化和解析 - 整洁! (2认同)

jmk*_*142 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
Run Code Online (Sandbox Code Playgroud)

有趣的部分可能会帮助你:

myShip.trigger('change');
    // general change
myShip.trigger('change:cas');
    // cas changed
Run Code Online (Sandbox Code Playgroud)

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