2012-04-26 30 views
10

我有一个模型集合,我希望在表格视图中呈现。每个模型应该由表中的单个行来表示,并且该行应该使用模板生成。我应该可以将事件处理程序附加到该行(例如单击),在事件发生时会警告有关与该行关联的模型的一些特定信息。消耗行视图的骨干表视图 - 如何构造?

我见过类似的事情的一种常见方式是将每一行分解到它自己的视图中,并拥有一个父视图(可以说在这种情况下的表)使用行视图来生成HTML包括在你的代码中。但我无法弄清楚这是如何与模板一起工作的。

在这种情况下,我无法将事件专门添加到RowView中,因为它没有提及dom元素(主干为this.el),它只是返回一个字符串。我怎样才能达到我想要的效果,同时使用最大容量的模板?

这个问题并不是专门针对事件,模板或使用嵌套视图,而是更多关于使用Backbone来实现这种输出的正确方法。

示例代码中(也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(); 

谢谢!

回答

11

处理视图层次结构的一种方法是让每个视图呈现其子项并将它们附加到其el。根据其模型/集合,这些事件将由每个视图处理。

要注入你的HTML作为视图el,从而控制容器元素,你可以使用setElement方法

setElementview.setElement(element)

如果你想申请一个骨干 视图到另一个DOM元素,请使用setElement,它也将创建缓存的$ el引用,并将视图的委托事件 从旧元素移动到新元素。

你的例子可以改写为

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

并有小提琴http://jsfiddle.net/9avm6/5/

+0

'setElement'是一件我一直缺少的 - 谢谢! – 2012-09-05 01:53:27

+0

真棒。一个问题,你可以详细说明_.bindAll调用吗?我知道在功能被调用的时候它应该使'这个'更有用,但是这种形式的调用意味着什么?绑定渲染和renderOne到哪些事件?你为什么要把renderOne绑定到任何东西上?非常感谢! – Nicolas78 2012-11-20 09:26:48

+0

@ Nicolas78 _.bindAll保证render和renderOne中的'this'是视图,而不是触发事件的元素。在这里不是很有用,没有设置绑定,但可以调用collection.reset和renderOne来渲染一个collection.add – nikoshr 2012-11-20 13:46:05