Backbone: événements en double lors de l'instanciation de la vue deux fois

Créé le 5 févr. 2012  ·  9Commentaires  ·  Source: jashkenas/backbone

Lorsque je définis une vue (via Backbone.View.extend) et que je l'instancie deux fois (via new), lorsqu'un événement se produit une fois sur chaque objet ivies, il est déclenché deux fois.

Petit exemple :

<html>
<head>
    <script type="text/javascript" src="js/jquery-1.7.1.js"></script>
    <script type="text/javascript" src="js/underscore-1.3.1.js"></script>
    <script type="text/javascript" src="js/backbone-0.9.1.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/javascript">
        testview = Backbone.View.extend ({
            el: '#test',
             events: {'click .test': 'doTest'},
             doTest: function() {alert('test')},
             render: function() {$('#test').append($('<a>').attr('href', '#').addClass('test').append('test'));}});
        view_one = new testview;
        view_two = new testview;
        view_one.render();
    </script>
    </body>
</html>

Tous les 9 commentaires

Par curiosité, pourquoi l'instanciez-vous deux fois ? Êtes-vous dans une vue mobile ou quelque chose où la première instance de la fenêtre est remplacée par une autre vue, et lorsque l'utilisateur revient à cette première vue, vous obtenez des doubles liaisons ?

Quelque chose comme ca. J'ai une vue d'accueil, qui appellera différents points de terminaison si l'utilisateur est connecté ou non. Les liaisons d'événements sont pour les boutons de connexion/déconnexion. Les deux vues sont instanciées mais une seule est rendue à la fois. Lorsqu'ils se connectent ou se déconnectent, je passe à la même vue mais dans un mode différent. J'espère que c'est assez clair.

Ce n'est toujours pas tout à fait clair pour moi, pourquoi vous avez les deux vues instanciées en même temps. Avoir les deux liés au même élément préexistant dans le dom signifie qu'il y aura des événements doubles. Ce n'est pas vraiment un bogue, mais juste la façon dont fonctionnent les événements et en particulier la délégation d'événements.

Si vous instanciez une vue sur un élément préexistant, vous devez spécifiquement dissocier ces événements ou ils persisteront jusqu'à ce que le nœud de l'élément lui-même soit supprimé du dom.

Eh bien, cela semblait être une bonne idée d'instancier les deux vues lors de l'initialisation, de lier les deux au même élément racine dans le DOM, puis de rendre l'un ou l'autre selon le mode de connexion et de le faire remplacer les autres éléments lors du rendu. Je suppose qu'il y a une meilleure façon de le faire, d'après vos commentaires.

J'instancierais des vues lorsque vous en avez besoin. Si une vue n'est pas utilisée, il n'est pas nécessaire de l'avoir pour occuper de la mémoire et potentiellement introduire des effets secondaires comme vous le voyez.

J'ai tendance à ne pas utiliser ce modèle:

var View = Backbone.View.extend ({
    el: '#test',
    events: 
    {
        'click .test': 'onClick'
    },
    onClick: function(event) 
    { 
        ... 
    }
});

view = new View;
view.render();

mais à la place, j'ai tendance à utiliser ce modèle, exactement pour éviter les vues zombies qui entraînent la duplication d'événements

var View = Backbone.View.extend ({
    events: 
    {
        'click .test': 'onClick'
    },
    onClick: function(event) 
    { 
        ... 
    }
});

view = new View;
$('#target').append(view.render().el);

Le seul emplacement où j'utiliserais votre premier modèle est dans la vue Chrome de l'application qui instancie l'interface graphique :

var Application = Backbone.View.extend({
    el: '#wrapper',
    initialize: function (options)
    {
        this.render();
    }
)};

$(document).ready(function () {
    window.application = new Application();
});

idem sur ce que @vincentbriglia a dit à propos de ne pas définir el et de laisser la vue générer son propre élément. Je le fais aussi 95% du temps. Si toutefois vous souhaitez définir el et nettoyer les événements lors de la suppression, vous pouvez définir votre propre méthode Backbone.View.destroy() avec un .off() pour chaque on() et chaque événement en events: {}

par example:

var MyView = Backbone.View.extend({

  initialize: function() {
    this.model.on('change', this.render, this);
  },

  render: function() {
    return this;
  },

  destroy: function() {
    this.remove();
    this.model.off('change', this.render, this);
  }
})

Merci, @malandrew et @vincentbriglia , ça aide vraiment.

Juste pour mettre à jour ceci pour la postérité... J'ai ajouté une méthode destroy à la classe View qui ressemble à ceci

           destroy: function() {
                this.undelegateEvents();
            }

Ensuite, je détruis simplement la vue actuelle (State.view) chaque fois que j'instancie ().

Cette page vous a été utile?
0 / 5 - 0 notes