2011-08-18 14 views
14

Tengo un método render en red troncal que va básicamente lo siguiente:Llamar a un plugin de jQuery en un Backbone rendir método

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

que se llama a partir de una acción del router:

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

Ahora, desea aplicar un complemento en label elementos dentro de esta vista. Mi primer pensamiento fue llamar el plugin dentro render:

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

pero esto no funciona (estoy suponiendo que esto se debe a que el elemento no se ha añadido a la DOM todavía). Se hace trabajo si llamo el plugin en la acción del router sin embargo:

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

prefiero no hacer esto, ya que el plugin es parte de la vista, no el router, por lo que no hace sentido para llamarlo dentro de la acción. ¿Hay una mejor manera de hacer esto?

Respuesta

0

He 'resuelto' este problema agregando un método loadPlugins a mi vista, por lo que puedo hacer myView.loadPlugins() después del renderizado en la acción. No es ideal, pero funciona.


Editar: Bueno, he heard from the horse's mouth y parece que no puedo aplicar el plug-in antes de que el elemento ha sido añadido a la DOM, por lo que cualquiera que pueda hacer que el anterior (con loadPlugins) o I puede modificar el código para que el elemento se agregue al DOM en el método render. Espero que esto ayude a alguien en una posición similar.

Así es como lo estoy haciendo ahora:

//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 hacerlo de esta manera:

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

Gracias - que es esencialmente lo que quiero decir con "modificar el código para la el elemento se agrega al DOM en el método 'render' Por cierto, puedes hacer 'this. $ ('Label')', que es una abreviatura de '$ ('label', this.el)'. – Skilldrick

+0

gracias! no lo sabe;) –

0

que estaba frente a un problema similar, pero en mi caso incluso las soluciones anteriores no lo haría funciona porque las vistas padre aún no se habían agregado al DOM.

Siguiendo con la convención de tener la vista principal agregar los elementos secundarios al DOM, al hacer loadPlugins() en el método de renderizado no funcionó.

Esto es lo que hice. Se siente un poco de hacky, pero podría ayudar, dependiendo de cómo se va a administrar sus puntos de vista a lo largo de la jerarquía:

render: function() { 
    var self = this; 

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

    return this; 
} 

El uso de un setTimeout de 0 permite que la pila de llamadas actual para terminar, de manera que cuando la función de tiempo de espera se pone llamada la vista y todos sus padres se han agregado al DOM. (Si te apegas a la convención mencionada anteriormente).

+0

Sería mejor si hubiera una forma de adjuntar un detector de eventos que se active cuando se haya agregado cierto elemento al DOM. ¿Alguien sabe de una manera de hacer esto? – evilcelery

+0

Sí, he estado pensando en hacer un setTimeout también, definitivamente funcionará, pero también se siente horriblemente hacky. – Skilldrick

+0

Parece que * hay * eventos para cuando [se ha agregado un elemento] (http://en.wikipedia.org/wiki/DOM_events) p. 'DOMNodeInserted', pero IE no los admite. Como siempre. Más información: http://stackoverflow.com/questions/2143929/domnodeinserted-equivalent-in-ie – Skilldrick

5

Me encontré con un problema similar al configurar el plugin jQuery Tools Tooltip. Pero tenía un enfoque muy diferente que funciona bien: activar un evento personalizado en la vista. Hasta donde yo sé, no hay un evento 'insertado en el dom' disparado integrado en Backbone, así que lo hice yo mismo.Yo no uso un router pero el código modificado anterior sería algo como esto:

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

supongo que la ventaja es que la vista permanece ignorante de su contenedor. La desventaja es que es como una línea extra o dos de código. Pero si necesita configurar una gran cantidad de complementos o hacer más cosas que requieren que el elemento esté en el DOM, funcionará bien (y mantiene la lógica separada).

De hecho, me gusta el método de @ Skilldrick para pasar el contenedor a la vista, pero todavía siento que tiene sentido que la vista padre sea responsable de insertar los elementos secundarios. Soy nuevo en Backbone, así que no dude en comentar.

+0

Es una idea interesante, pero no me gusta la idea de que el enrutador diga a la vista que se ha renderizado. ¡Eso solo parece fundamentalmente algo que la vista debería saber! – Skilldrick

+0

Sin embargo, es un buen compromiso si desea mantener el elemento contenedor fuera de la vista. – Skilldrick

+0

Correcto, es una compensación. Realmente no siento una atracción hacia un lado o el otro. Volveré a comentar si algo aparece en mi camino mientras uso mi aplicación. –

2

que era capaz de conseguir que esto funcione para mi plugin de jQuery solamente por especificando el contexto de jQuery en la función de render:

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

    return this; 
}, 
+2

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

Cuestiones relacionadas