web-dev-qa-db-fra.com

Backbone: événement perdu lors du re-rendu

J'ai super-vue qui est chargé de rendre sous-vues. Lorsque je re-rende le super-vue, tous les événements de la sous-vues sont perdus.

Ceci est un exemple:

var SubView = Backbone.View.extend({
    events: {
        "click": "click"
    },

    click: function(){
        console.log( "click!" );
    },

    render: function(){
        this.$el.html( "click me" );
        return this;
    }
});

var Composer = Backbone.View.extend({
    initialize: function(){
        this.subView = new SubView();
    },

    render: function(){
        this.$el.html( this.subView.render().el );             
    }
});


var composer = new Composer({el: $('#composer')});
composer.render();

Lorsque je clique sur le cliquez sur moidev, l'événement est déclenché. Si j’exécute à nouveau composer.render(), tout a l’air identique mais le clic sur l'événement n'est plus déclenché.

Vérifiez le de travail jsFiddle .

37
fguillen

Quand tu fais ça:

this.$el.html( this.subView.render().el );

Vous dites effectivement ceci:

this.$el.empty();
this.$el.append( this.subView.render().el );

et empty tue les événements sur tout ce qui se trouve à l'intérieur de this.$el:

Pour éviter les fuites de mémoire, jQuery supprime d'autres constructions telles que les gestionnaires de données et d'événements des éléments enfants avant de supprimer les éléments eux-mêmes.

Vous perdez donc l'appel delegate qui lie les événements sur this.subView et le SubView#render ne les reliera pas.

Vous devez insérer un appel this.subView.delegateEvents() dans this.$el.html() mais vous devez le faire après la empty(). Vous pouvez le faire comme ceci:

render: function(){
    console.log( "Composer.render" );
    this.$el.empty();
    this.subView.delegateEvents();
    this.$el.append( this.subView.render().el );             
    return this;
}

Démo: http://jsfiddle.net/ambiguous/57maA/1/

Ou comme ceci:

render: function(){
    console.log( "Composer.render" );
    this.$el.html( this.subView.render().el );             
    this.subView.delegateEvents();
    return this;
}

Démo: http://jsfiddle.net/ambiguous/4qrRa/

Ou vous pourriez remove et recréer le this.subView lors du rendu et éviter le problème de cette façon (mais cela pourrait causer d’autres problèmes ...).

64
mu is too short

Il existe une solution plus simple ici qui n’annule pas les inscriptions à un événement: jQuery.detach().

http://jsfiddle.net/ypG8U/1/

this.subView.render().$el.detach().appendTo( this.$el );   

Cette variation est probablement préférable pour des raisons de performances:

http://jsfiddle.net/ypG8U/2/

this.subView.$el.detach();

this.subView.render().$el.appendTo( this.$el );

// or

this.$el.append( this.subView.render().el );

Évidemment, il s’agit d’une simplification qui correspond à l’exemple dans lequel la vue secondaire est le seul contenu du parent. Si c'était vraiment le cas, vous pourriez simplement rendre à nouveau la vue secondaire. S'il y avait un autre contenu, vous pourriez faire quelque chose comme:

var children = array[];

this.$el.children().detach();

children.Push( subView.render().el );

// ...

this.$el.append( children );

ou

_( this.subViews ).each( function ( subView ) {

  subView.$el.detach();

} );

// ...

De plus, dans votre code d'origine, et répété dans la réponse de @ mu, un objet DOM est passé à jQuery.html(), mais cette méthode est uniquement documentée en tant qu'acceptant des chaînes de code HTML:

this.$el.html( this.subView.render().el );

Signature documentée pour jQuery.html():

.html( htmlString )

http://api.jquery.com/html/#html2

11
JMM

Lors de l'utilisation de $(el).empty(), tous les éléments enfants de l'élément sélectionné sont supprimés AND supprime ALL les événements (et les données) liés à à tout élément (enfant) inside de l'élément sélectionné (el).

Pour conserver les événements liés à les éléments enfants , tout en supprimant les éléments enfants, utilisez:

$(el).children().detach(); au lieu de $(.el).empty();

Cela permettra à votre vue de restituer avec succès les événements toujours liés et fonctionnant.

0
AmpT