2012-04-26 85 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