Backbone setElement删除事件

时间:2013-06-17 09:32:55

标签: javascript backbone.js

我可能在这里遗漏了一些微不足道的东西,但看起来setElement没有重新绑定事件,尽管文档和代码都说它应该。

我尝试用尽可能少的代码重新创建问题,但它仍然相当多,所以我在Gist上发布了它:

https://gist.github.com/gooli/baecc277d864e28eb2c7

当我单击其中一个复选框时,控制台上将显示“selected”。但是当我再次点击它时,它不会再输入事件。

我这样做是因为我真的希望模板包含<tr>元素而不仅仅是内部<td>元素。

当我删除<tr>元素,在视图中使用tagName: 'tr'并使用通用this.$el.html(...)公式进行渲染时,工作正常。

我错过了什么?

2 个答案:

答案 0 :(得分:2)

根据jakee的回答,我提出了一个更好的解决方案,不需要在render内重新实现模板逻辑。

window.DayView = Backbone.View.extend({
    template: Handlebars.compile($('#day-template').html()),
    events: {
        'click .select input': 'select'
    },
    initialize: function () {
        this.model.bind('change', this.render, this);
        this.setElement(this.template(this.model.toJSON()));
    },
    render: function() {
        console.log('render');
        this.$el.html($(this.template(this.model.toJSON())).html());
        return this;
    },
    select: function (event) {
        console.log('selected');
        this.model.set({selected:$(event.target).is(':checked')});
    }
});

initialize方法使用整个模板来创建元素。 render方法仅使用模板的内部html来呈现新值。

这看起来很干净,允许我在模板中定义所有视图的HTML而不依赖tagName。我是一个快乐的露营者。

答案 1 :(得分:1)

出于多种原因,您的方法存在问题。

this.model.each(function(day) {
  that.$el.append(new DayView({model:day}).render().$el);
});

您可以在此处将DayView元素附加到DayListView。您将每个视图的$el附加到父视图的$el。当子元素具有固定的包装元素时,这是标准的。这是您定义tagName属性的情况。但是当你不断重新分配视图的元素时,这是有问题的。

  1. 您将ItemView元素添加到父
  2. 您点击选择
  3. 为ItemView 调用
  4. undelegateEvents
  5. ItemView的$elel填充了新模板
  6. 为ItemView 调用
  7. delegateEvents

    现在导致问题的原因是:

    1. 旧的ItemView内容不会从父视图中删除
    2. 新的ItemView内容未添加到父视图
    3. 事件被委托给不在DOM中的元素
    4. 我的解决方案是:

      window.DayView = Backbone.View.extend({
        template: Handlebars.compile($('#day-template').html()),
        events: {
          'click .select input': 'select'
        },
        initialize: function () {
          this.model.bind('change', this.render, this);
          this.setElement(this.template(this.model.toJSON()));
        },
        render: function() {
          this.$el.find('.name').text(this.model.get('name'));
          this.$el.find('.select input').attr('checked', this.model.get('selected'));
          return this;
        },
        select: function (event) {
          this.model.set({selected:$(event.target).is(':checked')});
        }
      });
      

      这样,每次单击复选框时都不会替换视图元素。现在这个解决方案很可能远非最佳,但应该指向正确的方向。

      希望这有帮助!