2012-02-04 5 views
22

ecco, una vista dorsale di rendering chiamata:chiamando javascript sul rendering delle viste in BackBone js. callback post-rendering?

render: function() { 
    $(this.el).html(this.template({title: 'test'})); //#1 
    this.renderScatterChart(); 
    return this; 
}, 

così, io chiamo uno standard di rendering al # 1. e poi, chiamo un metodo [questa volta, è un wrapper per la creazione di grafici della lib] che cerca un div. il div è reso dalla chiamata di rendering. ma a questo punto, non è ancora collegato al DOM (giusto?). così la call del grafico muore tristemente.

qual è lo schema per questo? mi piacerebbe sapere che c'è una richiamata post-rendering. Ho provato alcuni hack intorno a questo, e a volte ho il grafico per funzionare, ma gli eventi non si legano.

risposta

45

Il mio approccio abituale per questo genere di cose è utilizzare setTimeout con un timeout pari a zero per fare in modo che qualcosa succeda quando il browser riprende il controllo. Prova questo:

render: function() { 
    $(this.el).html(this.template({title: 'test'})); 

    var _this = this; 
    setTimeout(function() { 
     _this.renderScatterChart(); 
    }, 0); 

    return this; 
} 

Oppure, se renderScatterChart è già legata alla appropriata this:

render: function() { 
    $(this.el).html(this.template({title: 'test'})); 
    setTimeout(this.renderScatterChart, 0); 
    return this; 
} 

È anche possibile utilizzare _.defer se si vuole essere più esplicito su ciò che stai facendo:

rinviare_.defer(function, [*arguments])

rinvia invocando la funzionefino a quando la pila chiamata corrente ha eliminato, simile ad usare setTimeout con un ritardo di 0.

Così si potrebbe anche fare in questo modo:

// Assuming that `renderScatterChart` is bound to the appropriate `this`... 
render: function() { 
    $(this.el).html(this.template({title: 'test'})); 
    _(this.renderScatterChart).defer(); 
    return this; 
} 

// or if it isn't bound... 
render: function() { 
    $(this.el).html(this.template({title: 'test'})); 

    var _this = this; 
    _(function() { 
     _this.renderScatterChart(); 
    }).defer(); 

    return this; 
} 
+3

omg. Sono incredulo che questo ha funzionato. – whatbird

+1

@whatbird: questo trucco 'setTimeout (..., 0)' imposta semplicemente una funzione da chiamare quando il tuo JavaScript è completo e il controllo ritorna al browser. Quindi il tuo codice imposterà tutto e aggiungerà tutto al DOM, quindi il browser prende il sopravvento e attiva la funzione ritardata. Questo trucco è un po 'un trucco ma utile. –

+0

L'hack non è necessario se si inserisce view.el nel DOM prima di eseguire il rendering. Non mi piace usare setTimeout hack, seguendo un buon flusso non è mai necessario. Controlla la mia risposta spiegando le differenze che eseguono il rendering prima di inserire .el e in esecuzione dopo l'inserimento. Un arresto anomalo e l'altro funziona normalmente, senza l'uso di setTimeout. ;) –

1

si potrebbe semplicemente fare questo (se renderSactterChart opera su un oggetto 'jQuery-ized'):

render: function() { 
    this.$el.html(this.template({title: 'test'})); //#1 
    this.$el.renderScatterChart(); 
    return this; 
}, 

(questo non è il vero elemento DOM ...)

1

Aveva lo stesso problema di te ... con i grafici alti. Stavo usando Backbone.LayoutManager e ho finito per hackerare il codice per aggiungere un callback postRender. Mi piacerebbe vedere questo come una parte di Backbone.js

0

Bene, questo è già stato risposto, ma per riferimento futuro ho avuto questo problema un paio di volte. Ho risolto con l'aggiunta di eventi personalizzati, in questo caso potrebbe essere qualcosa di simile a

render: function() { 
    $(this.el).html(this.template({title: 'test'})); //#1 

    this.on('someView:append', function() { 
     this.renderScatterChart(); 
    }, this); 

    return this; 
} 

E poi, quando aggiungo l'elemento al DOM, mi innescare come

myView.trigger('someView:append'); 

Ora, è certamente non una bella soluzione. Stai aggiungendo la responsabilità di attivare questo evento a qualsiasi cosa acceda alla visualizzazione renderizzata sul DOM. A seconda di come è strutturato il tuo codice, può adattarsi meglio o peggio. Ancora una volta, sto postando questo come un riferimento futuro e un'alternativa.

Maggiori informazioni: http://backbonejs.org/#Events

26

So che questo si risponde, ma ho pensato di condividere. Underscore js ti ha coperto con la funzione _.defer.

render: function() { 
    $(this.el).html(this.template({title: 'test'})); //#1 
    _.defer(function(view){ view.renderScatterChart();}, this); 
    return this; 
}, 

Secondo i documenti Underscore, questa è effettivamente la stessa cosa della soluzione accettata.

3

È perché si esegue il rendering prima che .el sia inserito nel DOM. Controllare il mio codice auto esplicative (eseguito in una pagina vuota con Backbone.js incluso):

function someThirdPartyPlugin(id){ 
    if($('#' +id).length ===0 ){ 
    console.log('Plugin crashed'); 
    }else{ 
    console.log('Hey no hacks needed!!!'); 
    } 
} 

var SomeView = Backbone.View.extend({ 
    id : 'div1', 
    render : function(){ 
     this.$el.append("<p>Hello third party I'm Backbone</p>"); 
     someThirdPartyPlugin(this.$el.attr('id')); 
     return this; 
    } 
}); 
var SomeView2 = Backbone.View.extend({ 
    id : 'div2', 
    render : function(){ 
     this.$el.append("<p>Hello third party I'm Backbone</p>"); 
     someThirdPartyPlugin(this.$el.attr('id')); 
     return this; 
    } 
}); 

var myView1 = new SomeView(); 
$('body').append(myView1.render().el); 
var myView2 = new SomeView2(); 
$('body').append(myView2.el); 
myView2.render(); 
1

Se non si desidera utilizzare il setTimeout hack, credo che in questo modo è più 'normale':

Basta passare l'elemento $ el alla funzione che deve modificare gli elementi aggiunti da render() e quindi la manipolazione DOM può essere eseguita su $ el.

0

Questo dovrebbe essere fatto in questo modo:

render: function() { 
    Marionette.ItemView.prototype.render.apply(this, arguments); 
    your code ... 
} 

campione con marionette, ma idea funziona per le viste backbone così

Problemi correlati