36 votes

Backbone.js: le changement ne se déclenche pas sur model.change ()

Je suis face à un "événement de changement de pas de tir" de l'émission sur Backbone.js =/

Ici mon point de vue de l'Utilisateur modèle :

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

        }

    });

Ici, le modèle de l'Utilisateur :

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

            }
        }
    });

Dans le modèle d'Utilisateur, il y a le "cas" de l'attribut, qui est un tableau d'objets.

J'ai lu dans d'autres sujets que les événements de changement ne sont pas le feu sur le modèle.définir si les attributs ne sont pas une valeur.

Alors, j'essaie de déclencher directement l'événement de changement de modèle.changement de méthode. Mais, je n'ai pas de "foo" journal de ma console ...

71voto

killthrush Points 689

Je suis assez nouveau à l'épine dorsale et j'ai eu ce même problème.

Après avoir fait quelques recherches, j'ai trouvé quelques posts qui ont versé un peu plus de lumière sur les raisons de cette situation, et, finalement, les choses ont commencé à faire sens:

Question 1

Question 2

Le cœur, la raison a à voir avec la notion de référence à l'égalité versus set/membre de l'égalité. Il semble que, dans une large mesure, la référence à l'égalité est l'une des principales techniques de la dorsale utilise pour savoir quand un attribut a changé.

Je trouve que si j'ai recours à des techniques qui génèrent une nouvelle référence de type Array.slice() ou _.clone(), le changement de l'événement est reconnu.

Ainsi, par exemple, le code suivant ne déclenche pas l'événement, car je suis modifiant la même référence de tableau:

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

Bien que ce code ne déclencher l'événement:

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

REMARQUE: Selon le trait de Soulignement de l'API, _.clone() des copies de certains éléments imbriqués par référence. La racine/objet parent est cloné, donc il fonctionnera très bien pour la colonne vertébrale. C'est, si votre tableau est très simple et ne possède pas de structures imbriquées par exemple [1, 2, 3].

Alors que mon amélioré le code ci-dessus déclenché le changement, les événements suivants n'est pas parce que mon tableau contenu des objets imbriqués:

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

Maintenant, pourquoi cette question? Après le débogage très attentivement, j'ai remarqué que dans mon itérateur je faisait référence à la même référence d'objet backbone a stocker. En d'autres mots, j'avais, par inadvertance, a atteint dans les entrailles de mon modèle et renversé un peu. Quand j'ai appelé setLabels(), de la colonne vertébrale correctement reconnu que rien n'a changé parce que déjà, elle savait que j'ai montré que peu.

Après avoir regardé autour de quelques-uns plus, les gens semblent dire en général que profond des opérations de copie en javascript sont une vraie douleur - rien à faire. J'ai donc fait cela, ce qui a bien fonctionné pour moi - applicabilité générale peut varier:

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

14voto

orangewarp Points 6065

Intéressant. J'aurais pensé qu' .set({cas:someArray}) aurait tiré un événement de changement. Comme vous l'avez dit, il ne semble pas, et je n'arrive pas à tirer à l' .change() MAIS, je peux obtenir les événements de travailler si je ne l' model.trigger('change') ou model.trigger('change:attribute')

Cela vous permettra de déclencher le changement de l'événement sans que l'aléatoire attribut hack.

Si quelqu'un pouvait expliquer ce qui se passe avec les événements, de la colonne vertébrale, et ce code, qui pourrait m'aider à apprendre quelque chose de trop... Voici un peu de 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

La partie intéressante qui pourrait vous aider:

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

Je trouve cela intéressant et j'espère que cette réponse va également engendrer certains perspicace explication dans les commentaires que je n'ai pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X