webentwicklung-frage-antwort-db.com.de

Backbone.js: Änderung wird bei model.change () nicht ausgelöst

Ich stehe vor dem Problem, dass bei Backbone.js kein Änderungsereignis ausgelöst wird. = /

Hier meine Sicht des Usermodells:

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

        }

    });

Hier das Benutzermodell:

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

            }
        }
    });

Im Benutzermodell gibt es das Attribut "cas", bei dem es sich um ein Array von Objekten handelt.

Ich habe in anderen Themen gelesen, dass Änderungsereignisse in model.set nicht ausgelöst werden, wenn Attribute keine Werte sind.

Daher versuche ich, das Änderungsereignis direkt mit der model.change () -Methode auszulösen. Aber ich habe kein "foo" -Log in meiner Konsole ...

35
Atyz

Ich bin ziemlich neu im Rückgrat und hatte das gleiche Problem.

Nachdem ich ein paar Nachforschungen angestellt hatte, fand ich einige Posts, die ein wenig mehr Aufschluss darüber gaben, warum dies geschah, und irgendwann machten die Dinge Sinn:

Frage 1

Frage 2

Der Hauptgrund hat mit dem Begriff der Referenzgleichheit gegenüber der Mengen-/Elementgleichheit zu tun. Es scheint, dass die Referenzgleichheit zu einem großen Teil eine der Haupttechniken ist, mit denen das Rückgrat herausfindet, wann sich ein Attribut geändert hat.

Wenn ich Techniken verwende, die eine neue Referenz erzeugen, wie Array.slice () oder _.clone (), wird das Änderungsereignis erkannt.

Der folgende Code löst beispielsweise das Ereignis nicht aus, da ich denselben Array-Verweis ändere:

this.collection.each(function (caseFileModel) {
    var labelArray = caseFileModel.get("labels");
    labelArray.Push({ Key: 1, DisplayValue: messageData });
    caseFileModel.set({ "labels": labelArray });
});

Während dieser Code das Ereignis auslöst:

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

HINWEIS: Gemäß nderscore API kopiert _.clone () bestimmte verschachtelte Elemente als Referenz. Das Stamm-/übergeordnete Objekt wird jedoch geklont, sodass es für das Backbone einwandfrei funktioniert. Das heißt, wenn Ihr Array sehr einfach ist und keine verschachtelten Strukturen aufweist, z. [1, 2, 3].

Während mein verbesserter Code oben das Änderungsereignis auslöste, war das Folgende nicht der Fall, weil mein Array verschachtelte Objekte enthielt:

var labelArray = _.clone(this.model.get("labels"));
_.each(labelArray, function (label) {
    label.isSelected = (_.isEqual(label, selectedLabel));
});
this.model.set({ "labels": labelArray });

Warum ist das wichtig? Nachdem ich sehr sorgfältig debuggt hatte, bemerkte ich, dass ich in meinem Iterator auf dasselbe Objekt verweise, das das Referenz-Backbone gespeichert hatte. Mit anderen Worten, ich hatte versehentlich in die Innereien meines Modells gegriffen und ein wenig gewendet. Als ich setLabels () aufgerufen habe, hat Backbone richtig erkannt, dass sich nichts geändert hat, weil es bereits wusste , dass ich dieses Bit umgedreht habe.

Nach einigem Hin und Her scheinen die Leute im Allgemeinen zu sagen, dass Deep-Copy-Operationen in Javascript ein echtes Problem sind - nichts Eingebautes, um dies zu tun. Also habe ich das gemacht, was für mich gut funktioniert hat - die allgemeine Anwendbarkeit kann variieren:

var labelArray = JSON.parse(JSON.stringify(this.model.get("labels")));
_.each(labelArray, function (label) {
    label.isSelected = (_.isEqual(label, selectedLabel));
});
this.model.set({ "labels": labelArray });
70
killthrush

Interessant. Ich hätte gedacht, dass .set({cas:someArray}) ein Änderungsereignis ausgelöst hätte. Wie Sie sagten, scheint dies nicht der Fall zu sein, und ich kann es nicht mit .change() zum Feuern bringen, ABER ich kann die Ereignisse zum Funktionieren bringen, wenn ich nur model.trigger('change') oder model.trigger('change:attribute')

Auf diese Weise können Sie das Änderungsereignis ohne diesen zufälligen Attribut-Hack auslösen.

Wenn jemand erklären könnte, was mit Ereignissen, Backbone und diesem Code los ist, würde mir das auch helfen, etwas zu lernen ... Hier ist ein Code.

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

Der interessante Teil, der Ihnen helfen könnte:

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

Ich finde das interessant und hoffe, dass diese Antwort auch einige aufschlussreiche Erklärungen in Kommentaren liefert, die ich nicht habe.

14
jmk2142