Backbone.js:事件中的this.model是第一个呈现的模型,而不是与DOM元素关联的模型

Backbone.js:事件中的this.model是第一个呈现的模型,而不是与DOM元素关联的模型,backbone.js,jsfiddle,Backbone.js,Jsfiddle,JSFiddle: 我正在尝试创建一个基本的购物车应用程序。单击某个项目时,我希望将其标题和价格添加到购物车表中 我正在为每个模型创建一个单独的视图实例。但是,单击项时,添加的表数据始终是item1模型的模型数据,而不是我希望与单击的DOM元素关联的模型数据。为了获得单击元素的模型数据,我必须更改什么 var-app=app | |{}; var Item=Backbone.Model.extend({ 默认值:{ 命令:“”, 标题:“”, 价格:0.01,, 化身:假 } }); var

JSFiddle:

我正在尝试创建一个基本的购物车应用程序。单击某个项目时,我希望将其标题和价格添加到购物车表中

我正在为每个模型创建一个单独的视图实例。但是,单击项时,添加的表数据始终是item1模型的模型数据,而不是我希望与单击的DOM元素关联的模型数据。为了获得单击元素的模型数据,我必须更改什么

var-app=app | |{};
var Item=Backbone.Model.extend({
默认值:{
命令:“”,
标题:“”,
价格:0.01,,
化身:假
}
});
var item1=新项目({订单:1,标题:“鞋子”,价格:30.00});
var item2=新项目({订单:2,标题:“袜子”,价格:5.00});
var item3=新项目({订单:3,标题:“衬衫”,价格:20.00});
var ItemsCollection=Backbone.Collection.extend({model:Item});
var items=新ItemsCollection([item1,item2,item3]);
app.ItemView=Backbone.View.extend({
模板:35;.template($(“#项目模板”).html()),
初始化:函数(){
this.render()
},
render:function(){
$(“#display”).append(this.template(this.model.attributes));
},
el:“集装箱”,
活动:{
“单击。标题”:“移动到艺术”
},
moveToCart:函数(e){
e、 停止即时复制();
var title=this.model.get(“title”);
var价格=此.model.get(“价格”);
$(“表格”)。追加(“+标题+”+价格+”);
}
});
var itemView1=newapp.ItemView({model:item1});
var itemView2=newapp.ItemView({model:item2});
var itemView3=newapp.ItemView({model:item3})

标题
价格

$


您的问题是所有的
应用程序.ItemView
共享相同的
el

app.ItemView = Backbone.View.extend({
    //...
    el: "#container",
事件通过委托绑定到
el
。结果是您的事件都很混乱,因为每个人都试图在同一元素上侦听同一事件

最简单的解决方案是将
移出
#项目模板
模板:

<script type="text/template" id="item-template">
    <p class="title"><%= title %></p>
    <p class="price">$<%= price %></p>
</script>
渲染
的末尾返回此
,这是标准做法,您可以这样说:

$x.append(view.render().el);
移动
$('#display').append(…)
调用一个级别也很常见,这有助于保持视图的自包含性。还要注意,我切换到了
this.model.toJSON()
,而不是
this.model.attributes
;假装
属性
不存在通常是一个好主意,这样您就不会意外地躲在主干网后面搞混了

更新的fiddle:

是您任务的另一个实现

我想您已经很清楚,初始化大量
主干是一种不好的做法。使用相同的
el
选择器查看
s

在我的实现中,我分离了项目视图和容器视图,因此您将有:

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

});
我猜您将动态地添加项目/产品集合,而不是逐个添加,这种方法将非常有用。注意,我在这里使用了缓存


另一个注意事项:如果您决定使用主干网实现应用程序/单页应用程序,您也需要尝试。它将为您自动化大量员工,并将节省大量时间。希望这有帮助。

Aha!现在您已经指出了这一点,很明显每个视图都应该有自己的el。谢谢你的帮助!提醒您在render中添加“returnthis”语句。我明白了,如果我需要添加很多项,您的解决方案会更好。非常感谢。谢谢你给我关于木偶的提示,我会仔细研究的。
this.collection.each(function(model){…},this)
都会比在
之间乱搞要好。each(collection)
,不是吗?您可能需要检查您的
回调实际上传递了什么,
。每个(集合,…)
集合。每个(…)
都不是完全相同的东西。@muistooshort-当然,u。每个(集合,…)和集合。每个(…)都不同。在fiddle中JS代码的最后,您会发现我将集合作为主干模型数组传递,所以我为什么使用第1版。对于主干。集合,我们需要使用第二个。当有集合时,将集合作为数组传递有点奇怪。在
集合
属性中存储数组会让任何有主干网体验的人感到困惑。
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>");
    }

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