Backbone: event lost in re-render

Mam super-View kto jest odpowiedzialny za renderowanie sub-Views . Kiedy ponownie renderuję, super-widok wszystkie zdarzenia w pod-widokach zostaną utracone.

Oto przykład:

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

Kiedy klikam w click me div zdarzenie zostanie wywołane. Jeśli wykonam composer.render()ponownie wszystko wygląda tak samo, ale click event nie jest już uruchamiany.

Sprawdź działające jsFiddle .

Author: fguillen, 2012-08-19

3 answers

Kiedy to zrobisz:

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

Skutecznie to mówisz:

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

I empty this.$el:

Aby uniknąć wycieków pamięci, jQuery usuwa inne konstrukcje, takie jak procedury obsługi danych i zdarzeń z elementów potomnych przed usunięciem samych elementów.

Więc tracisz delegate wywołanie, które wiąże zdarzenia na this.subView i SubView#render nie będzie ich ponownie.

Musisz wsunąć this.subView.delegateEvents() wezwanie do this.$el.html() ale musisz to zrobić po empty(). Można to zrobić tak:

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/

Lub tak:

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

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

Or you could remove i ponownie utworzyć this.subView podczas renderowania i ominąć problem w ten sposób (ale może to spowodować inne problemy...).

 64
Author: mu is too short,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-20 02:19:19

Jest tu prostsze rozwiązanie, które nie zdmuchnie rejestracji zdarzeń w pierwszej kolejności: jQuery.detach().

Http://jsfiddle.net/ypG8U/1/

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

Ta odmiana jest prawdopodobnie preferowana ze względu na wydajność:

Http://jsfiddle.net/ypG8U/2/

this.subView.$el.detach();

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

// or

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

Oczywiście jest to uproszczenie, które pasuje do przykładu, gdzie pod view jest jedyną zawartością rodzica. Gdyby tak było, mógłbyś po prostu ponownie renderować podgląd. Gdyby były inne treści można by zrobić coś takiego:

var children = array[];

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

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

// ...

this.$el.append( children );

Lub

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

  subView.$el.detach();

} );

// ...

Również, w Twoim oryginalnym kodzie i powtórzonym w odpowiedzi @mu, obiekt DOM jest przekazywany do jQuery.html(), ale ta metoda jest udokumentowana tylko jako akceptująca ciągi HTML:

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

Udokumentowany podpis dla jQuery.html():

.html( htmlString )

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

 11
Author: JMM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-20 22:46:36

Podczas używania $(el).empty()usuwa wszystkie elementy potomne w zaznaczonym elemencie i usuwa wszystkie zdarzenia (i dane), które są powiązane z dowolnymi elementami potomnymi wewnątrz zaznaczonego elementu (el).

Aby zachować zdarzenia związane z elementami potomnymi , ale nadal usunąć elementy potomne, użyj:

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

Pozwoli to na pomyślne przekierowanie widoku z wydarzeniami nadal związanymi i działającymi.

 0
Author: AmpT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-12 12:50:14