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

时间:2012-03-28 14:38:17

标签: 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');

        }

    });

这里是用户模型:

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事件。 但是,我的控制台中没有“foo”登录...

2 个答案:

答案 0 :(得分:70)

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

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

Question 1

Question 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]。

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

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

答案 1 :(得分: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

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

myShip.trigger('change');
    // general change
myShip.trigger('change:cas');
    // cas changed

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