【问题标题】:Backbone View Events Firing for Each Instance of a View为视图的每个实例触发的主干视图事件
【发布时间】:2012-06-27 15:13:09
【问题描述】:

A 有一个父视图 OpenOrderListView,它创建了具有 事件OpenOrderViews 实例。我想要获得的结果是当OpenOrderViewmarkCompleted 按钮被单击 时,会调用一个函数来告诉模型 设置该属性

该功能正在运行,但它正在父级 (OpenOrderListView) 内的所有 OpenOrderViews 上调用,而不仅仅是处理单击事件的视图。我怎样才能让这个事件只在被操作的视图上触发?

代码如下

window.OpenOrderListView = Backbone.View.extend({
    el: 'table.openOrders tbody',

    initialize: function() {
        _.bindAll(this,'render');
        this.render();
    },


    render : function() {
        var $openOrders

        var models = this.collection.open();

        for (var i = models.length - 1; i >= 0; i--) {
            console.log('model', models[i]);
            console.log("this.template", this.template);
            new OpenOrderView({'model': models[i], 'el': this.el});
        };

    }
});

window.OpenOrderView = Backbone.View.extend({
    initialize: function() {
        console.log('this', this);
        _.bindAll(this,'render',
                       'markCompleted',
                       'markInProgress');
        this.render();
    },

    events : {
        "click .markCompleted":  "markCompleted",
        "click .markInProgress": "markInProgress",
    },

    markCompleted: function(){
        console.log(this);
        this.model.markCompleted();
    },

    markInProgress: function(){
        console.log("markInProgress",this);
        this.model.markInProgress();
        console.log('markInProgress Complete');
    },

    template : 'template-openOrderView',

    render : function() {
        console.log("View Rendered");
        $(this.el).append(tmpl(this.template, this.model.toJSON()));
    }

   window.Order = Backbone.Model.extend({
    url: function(){ 
        return "/api/order/id/"+this.get("id");
    },

    isCompleted: function(){
        return this.get('status') == "completed";
    },

    isInProgress: function(){
        return this.get('status') == "inProgress";
    },

    isOpen: function(){
        return this.get('status') == "open";
    },

    markCompleted: function(){
        this.set({'status':"completed"});
        console.log('markCompleted');
        return this.save();
    },

    markInProgress: function(){
        this.set({'status':"inProgress"});
        console.log('markInProgress');
        return this.save();
    },

    markOpen: function(){
        this.set({'status':"open"});
        console.log('markOpen');
        return this.save();
    }

});

})

订单视图模板

<tr class="order">
<td class="preview hide_mobile">
    <a href="{%=o.api_url%}" title="{%=o.name%}" rel="gallery"><img src="{%=o.thumbnail_url%}"></a>
</td>
<td class="name">
    <a href="{%=o.api_url%}" title="{%=o.name%}">{%=o.name%}</a>
</td>
<td class="description"><span>{%=o.description%}</span></td>
<td class="hide_mobile date_added"><span>{%=o.date_added%}</span></td>
<td class="hide_mobile user"><span>{%=o.username%}</span></td>
<td class="status">
    <a class="btn modal-download" target="_blank" href="{%=o.url%}" title="{%=o.name%}" download="{%=o.name%}">
        <i class="icon-download"></i>
        <span>Download</span>
    </a>  
    <button class="markCancel btn btn-danger" data-type="{%=o.delete_type%}" data-url="{%=o.delete_url%}">
        <i class="icon-remove icon-white"></i>
        <span>Cancel</span>
    </button>   
    <button class="markInProgress btn btn-primary" data-type="" data-url="">
        <i class="icon-repeat icon-white"></i>
        <span>Mark In Progress</span>
    </button>    
    <button class="markCompleted btn btn-success" data-type="" data-url="">
        <i class="icon-ok icon-white"></i>
        <span>Mark Completed</span>
    </button>
</td>

【问题讨论】:

    标签: events backbone.js views


    【解决方案1】:

    所有SubViews 共享同一个DOM 元素table.openOrders tbody。这是在new OpenOrderView({'model': models[i], 'el': this.el}); 行中完成的。

    所以当你声明这样的事件时:

    events : {
        "click .markCompleted":  "markCompleted"
    }
    

    发生的情况是,与此 table.openOrders tbody .markCompleted 匹配的所有 DOM 元素都将与此 click 事件绑定。

    您需要每个SubView 都有自己的this.el DOM 元素。

    在您的情况下,我认为如果您的子视图像这样在空中创建自己的 DOM 元素会更好:

    // code simplified an not tested
    window.OpenOrderView = Backbone.View.extend({
      tagName: 'tr',
      attributes: { class: "order" },
    
      initialize: function(){
        // don't render() here
      },
    
      // ... rest of your code
    
      render: function(){
        this.$el.html(tmpl(this.template, this.model.toJSON()));
        return this;
      }
    })
    

    看看现在SubView 本身不是渲染,也不是附加它的DOM元素直接到页面,这将是ParentView的工作:

    // code simplified an not tested
    window.OpenOrderListView = Backbone.View.extend({
      render : function() {
        var $openOrders
    
        var models = this.collection.open();
    
        for (var i = models.length - 1; i >= 0; i--) {
          var openOrderView = new OpenOrderView({'model': models[i]});
          this.$el.append( openOrderView.render().el );
        };
    });
    

    我认为这是一种很常见的模式。

    PD:您必须修改模板删除 tr 打开/关闭。

    【讨论】:

    • 非常感谢。这有助于我更好地理解引擎盖下发生的事情!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多