2014-11-03 88 views
0

的jsfiddle关联的模型,:http://jsfiddle.net/umgauper/jnf8B/743/Backbone.js的:this.model事件是第一个模型渲染,而不是与DOM元素

我试图创建一个基本的购物车应用程序。点击某件商品时,我希望将其标题和价格添加到购物车表中。

我正在为每个模型创建一个单独的视图实例。但是,当单击某个项目时,添加的表格数据始终是item1模型的模型数据,而不是我期望与单击的DOM元素关联的模型数据。为了获得点击元素的模型数据,我需要做些什么改变?

var app = app || {}; 
 
var Item = Backbone.Model.extend({ 
 
    defaults: { 
 
     order: '', 
 
     title: '', 
 
     price: 0.01, 
 
     inCart: false 
 
      } 
 
}); 
 

 

 
var item1 = new Item({order: 1, title: "shoes", price: 30.00}); 
 
var item2 = new Item({order: 2, title: "socks", price: 5.00}); 
 
var item3 = new Item({order: 3, title: "shirt", price: 20.00}); 
 

 
var ItemsCollection = Backbone.Collection.extend({model: Item}); 
 

 
var items = new ItemsCollection([item1, item2, item3]); 
 

 
app.ItemView = Backbone.View.extend({ 
 
    template: _.template($("#item-template").html()), 
 
    initialize: function() { 
 
     this.render() 
 
    }, 
 
    render: function() { 
 
     $("#display").append(this.template(this.model.attributes)); 
 
    }, 
 
    el: "#container", 
 
    events: { 
 
     'click .title': 'moveToCart' 
 
    }, 
 
    moveToCart: function(e) { 
 
     e.stopImmediatePropagation(); 
 
     var title = this.model.get("title"); 
 
     var price = this.model.get("price"); 
 
     $("table").append("<tr><td>" + title + "</td><td>" + price + "</td></tr>"); 
 
    } 
 
}); 
 

 

 
var itemView1 = new app.ItemView({model: item1}); 
 
var itemView2 = new app.ItemView({model: item2}); 
 
var itemView3 = new app.ItemView({model: item3});
<div id="container"> 
 
    <div id="display"> 
 

 
    </div> 
 
    <table id="cart"> 
 
     <thead> 
 
     <th>Title</th> 
 
     <th>Price</th> 
 
     </thead> 
 

 
    </table> 
 
    </div> 
 
    <script type="text/template" id="item-template"> 
 
    <div> 
 
     <p class="title"><%= title %></p> 
 
     <p class="price">$<%= price %></p> 
 
    </div> 
 
    </script>

回答

0

你的问题是,所有的app.ItemView份额相同el

app.ItemView = Backbone.View.extend({ 
    //... 
    el: "#container", 

和事件通过代表团绑定到el。结果就是你的事件都被混淆了,因为每个人都试图在同一个元素上听同一个事件。

最简单的解决方案是将<div>搬出你的#item-template模板:

<script type="text/template" id="item-template"> 
    <p class="title"><%= title %></p> 
    <p class="price">$<%= price %></p> 
</script> 

,并使其成为elItemView。如果您没有以任何其他方式指定el,主干视图会创建一个空的<div>作为其el,因此您可以从ItemView删除el声明。你想也需要调整render占新结构:

render: function() { 
    this.$el.append(this.template(this.model.toJSON())); 
    $('#display').append(this.el); 
    return this; 
} 

return thisrender到底是标准的做法,这样你可以说这样的话:

$x.append(view.render().el); 

移动$('#display').append(...)调出一个级别也是常见的,并有助于保持视图的独立性。另外请注意,我切换到this.model.toJSON()而不是this.model.attributes;假装attributes不存在通常是一个好主意,这样你就不会意外地将Backbone背后的东西混淆了。

更新小提琴:http://jsfiddle.net/ambiguous/cad0kxee/

+0

啊哈!现在你已经指出了,似乎每个视图都应该有自己的el。谢谢你的帮助!并提醒在渲染中添加'return this'语句。 – unamaga 2014-11-03 19:41:53

0

Here是你的任务的另一种实现方式。

我想你已经很清楚,用相同的el选择器初始化很多Backbone.View是不好的做法。

我在执行我已经分居项目视图和容器视图,以便您将有:

app.ContentView = Backbone.View.extend({ 
    template: _.template($("#item-template").html()), 
    render: function() { 
     this.$el.append(this.template(this.model.attributes)); 
     return this; 
    }, 
    events: { 
     'click .title': 'moveToCart' 
    }, 
    moveToCart: function(e) { 
     e.stopImmediatePropagation(); 
     var title = this.model.get("title"); 
     var price = this.model.get("price"); 
     $("table").prepend("<tr><td>" + title + "</td><td>" + price + "</td></tr>"); 
    } 

}); 

和“的CollectionView”

app.ContentsView = Backbone.View.extend({ 
    initialize: function() { 
     this.render() 
    }, 
    render: function() { 
     var that = this; 
     this.buffer = document.createDocumentFragment(); 
     this.collection.each(function(model){ 
      var itemView = new app.ContentView({model: model}); 
      that.buffer.appendChild(itemView.render().el); 
     }); 
     this.$el.append(this.buffer); 
    }, 
    el: "#display" 
}); 

我猜你会添加的项目/产品集合动态,而不是一个一个,这种方法将是有帮助的。请注意,我在此处使用了documentFragment进行缓存。

另一注意事项:如果您决定使用Backbone来实现应用程序/单页应用程序,则还需要尝试Backbone.Marionette。它会为你自动化很多员工,并且会节省很多时间。希望这可以帮助。

+0

我看到,如果我需要添加大量项目,您的解决方案会更好。谢谢!感谢关于木偶的小贴士 - 我会研究它。 – unamaga 2014-11-03 19:53:49

+0

'this.collection.each(function(model){...},this)'会比'that'和'_.each(collection,...)'搞乱,不是吗?你可能想检查你的'_.each'回调实际上是否已经通过,'_.each(collection,...)'和'collection.each(...)'不是完全一样的东西。 – 2014-11-03 20:13:51

+0

@ muistooshort - 当然,_each(collection,...)和collection.each(...)是不同的。在小提琴中的JS代码的末尾,你会发现我将集合作为骨干模型的数组传递,所以为什么我使用了第一个版本。在Backbone.Collection的情况下,我们需要使用第二个。 – 2014-11-03 20:55:49

相关问题