2011-08-18 2 views
14

Ho un metodo di rendering in Backbone che va sostanzialmente in questo modo:Chiamare un plugin jQuery in un Backbone render metodo

render: function() { 
    $.tmpl(this.template, attrs).appendTo(this.el); 
    return this; 
}, 

che viene chiamato da un'azione di router:

action: function() { 
    $('#container').empty(); 
    $('#container').append(myView.render().el); 
}, 

Ora, desidera applicare un plug-in su elementi label all'interno di questa vista. Il mio primo pensiero è stato quello di lanciare il plugin all'interno render:

render: function() { 
    $.tmpl(this.template, attrs).appendTo(this.el); 
    this.$('label').inFieldLabels(); 
    return this; 
}, 

, ma questo non funziona (sto assumendo questo è perché l'elemento non è stato aggiunto al DOM ancora). Si fa lavoro se chiamo il plugin nell'azione router però:

action: function() { 
    $('#container').empty(); 
    $('#container').append(myView.render().el); 
    myView.$('label').inFieldLabels(); 
}, 

preferirei non fare questo, perché il plugin è parte della vista, non il router, in modo da non fare senso di chiamarlo all'interno dell'azione. C'è un modo migliore per farlo?

risposta

0

Ho risolto questo problema aggiungendo un metodo loadPlugins alla mia visualizzazione, quindi posso eseguire myView.loadPlugins() dopo il rendering nell'azione. Non è l'ideale, ma funziona.


Edit: Beh, ho heard from the horse's mouth e sembra che non è possibile applicare il plugin prima che l'elemento è stato aggiunto al DOM, quindi o posso fare come sopra (con loadPlugins) o io può modificare il codice in modo che l'elemento venga aggiunto al DOM nel metodo render. Spero che questo aiuti qualcuno in una posizione simile.

ecco come lo sto facendo ora:

//in router 
action: function() { 
    var myView = new MyView({ 
    el: '#container' 
    }); 
} 

//in view 
render: function() { 
    $.tmpl(this.template, attrs).appendTo(this.el); //this now appends to the DOM 
    this.loadPlugins(); 
    return this; 
}, 

loadPlugins: function() { 
    this.$('label').inFieldLabels(); 
    //and other plugins 
}, 
5

Beter fare in questo modo:

action: function() { 
    var container = $('#container'); 

    container.empty(); 
    myView.render(container); 
}, 

render: function (container) { 
    $(this.el) 
     .append($.tmpl(this.template, attrs)) 
     .appendTo(container); 
    $('label', this.el).inFieldLabels(); 
    return this; 
}, 
+1

Grazie - che è essenzialmente ciò che intendo per "modificare il codice in modo che il l'elemento viene aggiunto al DOM nel metodo 'render'". Per inciso, si può semplicemente fare 'this. $ ('Label')', che è una scorciatoia per '$ ('label', this.el)'. – Skilldrick

+0

grazie! non lo sa;) –

0

stavo affrontando un problema simile, ma nel mio caso anche le soluzioni di cui sopra no lavoro perché le viste genitore non erano ancora state aggiunte al DOM.

Attenendosi alla convenzione di avere la vista genitore aggiungere i figli al DOM, facendo loadPlugins() nel metodo di rendering non ha funzionato.

Questo è quello che ho fatto. Ci si sente tipo di hacky, ma potrebbe aiutare, a seconda di come si sta gestendo le vostre opinioni in tutta la gerarchia:

render: function() { 
    var self = this; 

    setTimeout(function() { 
    $(self.el).setupPlugin(); 
    }, 0); 

    return this; 
} 

Utilizzando un setTimeout di 0 permette alla corrente stack di chiamate per finire, quindi per il momento la funzione di timeout diventa ha chiamato la vista e tutti i suoi genitori sono stati aggiunti al DOM. (Se si attenersi alla convenzione di cui sopra).

+0

Sarebbe meglio se esistesse un modo per collegare un listener di eventi che si attiva quando un determinato elemento è stato effettivamente aggiunto al DOM. Qualcuno sa di un modo per farlo? – evilcelery

+0

Sì, stavo pensando anche a fare un setTimeout - funzionerà sicuramente ma si sentirà anche orribilmente hacky. – Skilldrick

+0

Sembra che ci siano * eventi * per quando [un elemento è stato aggiunto] (http://en.wikipedia.org/wiki/DOM_events) ad es. 'DOMNodeInserted', ma non sono supportati da IE. Come sempre. Altre informazioni: http://stackoverflow.com/questions/2143929/domnodeinserted-equivalent-in-ie – Skilldrick

5

Ho riscontrato un problema simile durante l'installazione del plug-in Tooltip di jQuery Tools. Ma ho avuto un approccio molto diverso che funziona bene: l'attivazione di un evento personalizzato sulla vista. Per quanto ne so, non esiste un evento "inserito in dom" incorporato in Backbone, quindi l'ho fatto da solo.Io non uso un router, ma il codice modificato di cui sopra sarebbe simile a questa:

// In the router: 
action: function() { 
    var container = $('#container'); 

    container.append(myView.render().el)); 
    myView.trigger('rendered'); 
}, 

// In the view: 
initialize: function() { 
    this.bind('rendered', this.afterRender, this); 
}, 
render: function (container) { 
    $(this.el).append($.tmpl(this.template, attrs)) 
    return this; 
}, 
afterRender: function() { 
    $('label', this.el).inFieldLabels(); 
} 

Suppongo che il vantaggio è che la visione rimane ignorante del suo contenitore. Lo svantaggio è che è come una linea aggiuntiva o due di codice. Ma se hai bisogno di configurare molti plugin o fare più cose che richiedono che l'elemento sia nel DOM, funzionerà bene (e mantiene la logica separata).

In realtà mi piace il metodo @ Skilldrick di passare il contenitore alla vista, ma mi sento ancora come se avesse senso avere la vista genitore responsabile per l'inserimento dei bambini. Sono nuovo a Backbone quindi non esitate a commentare.

+0

È un'idea interessante, ma non mi piace l'idea che il router debba dire che è stato reso. Questo sembra fondamentalmente qualcosa di cui la vista dovrebbe sapere! – Skilldrick

+0

È un buon compromesso se si desidera mantenere l'elemento contenitore fuori dalla vista. – Skilldrick

+0

Esatto, è un compromesso. Non provo veramente attrazione per il modo o l'altro. Commenterò di nuovo se mi viene in mente qualcosa mentre eseguo la mia app. –

2

sono stato in grado di ottenere questo a lavorare per il mio plugin per jQuery solo dal specificando il contesto per jQuery nella funzione di rendering:

render: function() { 
    $(this.el).html(this.template(this.model.toJSON())); 
    $('#email1dropdown', this.el).dropdownify(); 

    return this; 
}, 
+2

Usa la scorciatoia 'this. $ (" # Email1dropdown ")'. – Matthew