wake-up-neo.com

Backbone: Ereignis beim erneuten Rendern verloren

Ich habe super-View wer ist für das Rendern von Sub-Views zuständig. Wenn I erneutes Rendern der Super-View ist, gehen alle Ereignisse in den Sub-Views verloren.

Dies ist ein Beispiel:

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

Wenn ich in das click me div klicke, wird das Ereignis ausgelöst. Wenn ich composer.render() erneut ausführen, sieht alles ziemlich gleich aus, aber das click event wird nicht mehr ausgelöst.

Überprüfen Sie das Working jsFiddle .

37
fguillen

Wenn du das machst:

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

Sie sagen effektiv:

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

und empty beendet alle Ereignisse in this.$el:

Um Speicherverluste zu vermeiden, entfernt jQuery andere Konstrukte wie z. B. Daten- und Ereignishandler aus den untergeordneten Elementen, bevor sie die Elemente selbst entfernen.

Sie verlieren also den delegate-Aufruf, der Ereignisse in this.subView bindet, und der SubView#render bindet sie nicht erneut.

Sie müssen einen this.subView.delegateEvents()-Aufruf in this.$el.html() ablegen, müssen dies aber nach der empty() tun. Du könntest es so machen:

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

Demo: http://jsfiddle.net/ambiguous/57maA/1/

Oder so:

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

Demo: http://jsfiddle.net/ambiguous/4qrRa/

Oder Sie könnten remove und den this.subView beim Rendern neu erstellen und das Problem auf diese Weise umgehen (dies könnte jedoch andere Probleme verursachen ...).

64
mu is too short

Es gibt hier eine einfachere Lösung, die die Ereignisregistrierungen von vornherein nicht beeinträchtigt: jQuery.detach().

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

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

Diese Variation ist jedoch wahrscheinlich aus Gründen der Leistung zu bevorzugen:

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

this.subView.$el.detach();

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

// or

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

Offensichtlich ist dies eine Vereinfachung, die dem Beispiel entspricht, bei dem die Unteransicht der einzige Inhalt des übergeordneten Elements ist. Wenn dies wirklich der Fall war, können Sie die Unteransicht einfach erneut rendern. Wenn es andere Inhalte gäbe, könnten Sie Folgendes tun:

var children = array[];

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

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

// ...

this.$el.append( children );

oder

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

  subView.$el.detach();

} );

// ...

In Ihrem ursprünglichen Code und in @ mus Antwort wiederholt, wird ein DOM-Objekt an jQuery.html() übergeben. Diese Methode wird jedoch nur als akzeptierte HTML-Zeichenfolgen dokumentiert:

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

Dokumentierte Signatur für jQuery.html():

.html( htmlString )

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

11
JMM

Bei Verwendung von $(el).empty() werden alle untergeordneten Elemente im ausgewählten Element AND entfernt. ALL the events (und Daten), die an beliebige (untergeordnete) Elemente gebunden sind inside des ausgewählten Elements (el).

Um die Ereignisse an the child elements zu binden, die untergeordneten Elemente jedoch zu entfernen, verwenden Sie:

$(el).children().detach(); statt $(.el).empty();

Auf diese Weise kann Ihre Ansicht erfolgreich erneut gerendert werden, wobei die Ereignisse weiterhin gebunden sind und funktionieren.

0
AmpT