2012-04-26 12 views
10

Tengo una colección de modelos que deseo mostrar en una vista de tabla. Cada modelo debe estar representado por una sola fila en la tabla, y esta fila debe generarse utilizando una plantilla. Debería ser capaz de adjuntar manejadores de eventos a esa fila (por ejemplo, hacer clic), que luego de un evento alertan sobre cierta información específica con respecto al modelo asociado con esa fila.Vista de tabla de backbone consumiendo vista de fila - ¿cómo estructurar?

Una manera común en que he visto cosas similares a esto es dividir cada fila en su propia vista, y tener una vista principal (digamos la tabla en este caso) usar la vista de fila para generar el html incluir en tu código. Sin embargo, no puedo entender cómo funciona esto con las plantillas.

En este caso, no puedo adjuntar eventos específicamente al RowView ya que no hace referencia a un elemento dom (this.el para la red troncal), simplemente devuelve una cadena. ¿Cómo puedo lograr lo que quiero, mientras uso una plantilla a la capacidad máxima?

La pregunta no es específicamente sobre eventos, creación de plantillas o uso de vistas anidadas, sino más sobre la forma correcta de utilizar Backbone para lograr este tipo de resultados.

Código de la muestra (también en un fiddle):

/** View representing a table */ 
var TableView = Backbone.View.extend({ 
    tagName: 'table', 
    render: function() { 
     var rows = _.map(this.collection.models, function(p) { 
      return new RowView({model: p}).render();       
     }); 
     $('body').html(this.$el.html(rows.join(''))); 
    } 
}); 

/** View representing a row of that table */ 
var RowView = Backbone.View.extend({ 
    render: function() { 
     // imagine this is going through a template, but for now 
     // lets just return straight html. 
     return '<tr>' + 
       '<td>' + this.model.get('name') + '</td>' + 
       '<td>' + this.model.get('age') + '</td>' + 
       '</tr>'; 
    } 
}); 

var data = [ 
    {'name': 'Oli', 'age': 25}, 
    {'name': 'Sarah', 'age': 20}]; 

/** Collection of models to draw */ 
var peopleCollection = new Backbone.Collection(data); 
var tableView = new TableView({collection: peopleCollection}); 
tableView.render(); 

Gracias!

Respuesta

11

Una forma de manejar una jerarquía de vistas es hacer que cada vista represente sus elementos secundarios y anexarlos a su el. Los eventos son manejados por cada vista, de acuerdo con su modelo/colección.

para inyectar código HTML como la vista el y así controlar el elemento contenedor, puede utilizar el método de setElement

setElementview.setElement(element)

Si desea solicitar una vista Backbone a un elemento DOM diferente, use setElement, que también creará la referencia $ el en caché y moverá los eventos delegados de la vista del elemento anterior al nuevo.

Tu ejemplo podría reescribirse como

var rowTemplate=_.template("<tr>"+ 
    "<td class='name'><%= name %></td>"+ 
    "<td class='age'><%= age %></td>"+ 
    "</tr>"); 

/** View representing a table */ 
var TableView = Backbone.View.extend({ 
    tagName: 'table', 

    initialize : function() { 
     _.bindAll(this,'render','renderOne'); 
    }, 
    render: function() { 
     this.collection.each(this.renderOne); 
     return this; 
    }, 
    renderOne : function(model) { 
     var row=new RowView({model:model}); 
     this.$el.append(row.render().$el); 
     return this; 
    } 
}); 

/** View representing a row of that table */ 
var RowView = Backbone.View.extend({ 
    events: { 
     "click .age": function() {console.log(this.model.get("name"));} 
    }, 

    render: function() { 
     var html=rowTemplate(this.model.toJSON()); 
     this.setElement($(html)); 
     return this; 
    } 
}); 

var data = [ 
    {'name': 'Oli', 'age': 25}, 
    {'name': 'Sarah', 'age': 20}]; 

/** Collection of models to draw */ 
var peopleCollection = new Backbone.Collection(data); 
var tableView = new TableView({collection: peopleCollection}); 
$("body").append(tableView.render().$el); 

Y un violín http://jsfiddle.net/9avm6/5/

+0

'setElement' era la pieza que había estado perdiendo - gracias! –

+0

impresionante. una pregunta, ¿pueden dar más detalles sobre la llamada _.bindToda? Entiendo que se supone que hace que "esto" sea más útil en el momento en que se llaman las funciones, pero ¿qué significa la llamada en esa forma? ¿A qué eventos se vincula render y renderOne? ¿Por qué vincular renderOne a algo? ¡Muchas gracias! – Nicolas78

+0

@ Nicolas78 _.bindAll garantiza que 'this' en render y renderOne será la vista, y no el elemento que desencadenó el evento, por ejemplo. No es muy útil aquí, no se establece ningún enlace, pero se podría invocar el render en un collection.reset, y renderOne en un collection.add – nikoshr

Cuestiones relacionadas