Javascript 将项目插入到backbone.js集合中

Javascript 将项目插入到backbone.js集合中,javascript,backbone.js,Javascript,Backbone.js,是否有一种简单的方法可以将新模型项插入到backbone.js集合的中间,然后更新集合的视图以将新项包含在正确的位置 我正在使用一个控件从列表中添加/删除项目。每个列表项都有自己的模型和视图,整个集合也有一个视图 每个项目视图都有一个Duplicate按钮,该按钮克隆项目的模型,并将其插入到已单击项目下方索引位置的集合中 将该项插入集合很简单,但我很难弄清楚如何更新集合视图。我一直在尝试这样的事情: ListView = Backbone.View.extend({ el: '#list

是否有一种简单的方法可以将新模型项插入到backbone.js
集合的中间,然后更新集合的
视图
以将新项包含在正确的位置

我正在使用一个控件从列表中添加/删除项目。每个列表项都有自己的
模型
视图
,整个集合也有一个
视图

每个项目视图都有一个
Duplicate
按钮,该按钮克隆项目的模型,并将其插入到已单击项目下方索引位置的集合中

将该项插入集合很简单,但我很难弄清楚如何更新集合视图。我一直在尝试这样的事情:

ListView = Backbone.View.extend({
    el: '#list-rows',
    initialize: function () {
      _.bindAll(this);
      this.collection = new Items();
      this.collection.bind('add', this.addItem);
      this.render();
    },
    render: function () {
      this.collection.each(this.addItems);
      return this;
    },
    addItem: function (item) {
      var itemView = new ItemView({ model: item }),
          rendered = itemView.render().el,
          index = this.collection.indexOf(item),
          rows = $('.item-row');

      if (rows.length > 1) {
        $(rows[index - 1]).after(rendered);
      } else {
        this.$el.append(rendered);
      }
    }
}
ListView = Backbone.View.extend({
  el: '#list-rows'
  , initialize: function () {
    _.bindAll(this);
    this.collection = new Items();
    this.collection.bind('add', this.render);
    this.render();
  }
  , render: function () {
    this.$el.empty();
    var self = this;
    this.collection.each(function(item) {
      self.$el.append(new ItemView({ model: item }).render().el);
    });
    return this;
  }
}
这个实现在某种程度上是可行的,但是当我添加一个新项目时,我发现了一些奇怪的bug。我相信我能解决这些问题,但是

我脑子里有个声音一直在告诉我有更好的办法。必须手动确定在何处插入新的
ItemView
似乎真的很麻烦——集合视图不应该已经知道如何重新提交集合了吗


有什么建议吗?

我通常的做法是让
列表视图
在其
渲染
函数中渲染每个
项目视图
。然后我将
add
事件绑定到
render
函数,如下所示:

ListView = Backbone.View.extend({
    el: '#list-rows',
    initialize: function () {
      _.bindAll(this);
      this.collection = new Items();
      this.collection.bind('add', this.addItem);
      this.render();
    },
    render: function () {
      this.collection.each(this.addItems);
      return this;
    },
    addItem: function (item) {
      var itemView = new ItemView({ model: item }),
          rendered = itemView.render().el,
          index = this.collection.indexOf(item),
          rows = $('.item-row');

      if (rows.length > 1) {
        $(rows[index - 1]).after(rendered);
      } else {
        this.$el.append(rendered);
      }
    }
}
ListView = Backbone.View.extend({
  el: '#list-rows'
  , initialize: function () {
    _.bindAll(this);
    this.collection = new Items();
    this.collection.bind('add', this.render);
    this.render();
  }
  , render: function () {
    this.$el.empty();
    var self = this;
    this.collection.each(function(item) {
      self.$el.append(new ItemView({ model: item }).render().el);
    });
    return this;
  }
}

每次调用
this.collection.add(someModel,{at:index})
,视图都会相应地重新呈现。

我认为在添加新元素时重新呈现整个集合不是最好的解决方案。这比在正确的位置插入新项目要慢,尤其是当列表很长时

也考虑下面的场景。在集合中加载一些项目,然后添加更多项目(假设用户单击“加载更多”按钮)。为此,您可以调用

fetch()
方法,将
add:true
作为选项之一。当从服务器接收到数据时,“添加”事件将被触发
n次
,最后您将重新呈现列表
n次

实际上,我在您的问题中使用了一种代码变体,下面是我对“add”事件的回调:

var view, prev, prev_index;
view = new ItemView({ model: new_item }).render().el;
prev_index = self.model.indexOf(new_item) - 1;
prev = self.$el.find('li:eq(' + prev_index + ')');
if (prev.length > 0) {
    prev.after(view);
} else {
    self.$el.prepend(view);
}

因此,本质上,我只是使用
:eq()
jQuery选择器,而不是像您那样获取所有元素,应该使用更少的内存。

我必须在
render
方法中添加对
(.item row).remove()
的调用,以使其工作,但这是一个很好的解决方案。(否则,重新渲染的项目将添加到现有渲染项目的末尾。)感谢您的帮助!哦,您可以执行
此操作。$el.empty()
在循环遍历集合之前清除
$el
:)这正是我当前向集合添加项目的方式。这是把新的项目在正确的地点收集。我注意到我在上面的评论中有几个输入错误:我正在调用
$('.item row').remove()
,以清除上次呈现集合时创建的项目。这只是重置视图。想想看,有一个
reset
方法可以实现我想要的功能。我将尝试调用它,然后调用
render
。这并不理想,因为当只添加一个模型时,它会重新渲染整个集合视图。我想这一切都取决于我们希望如何解决问题。如果JavaScript/jQuery试图找到插入和删除某个模型视图的确切位置,您可能会发疯。或者,如果模型数量较少,则清除整个内容并重新渲染似乎不太糟糕。这很好,但我会在列表中的每个项目旁边显示数字,因此我需要重新渲染以保持数字同步。我看不出有什么办法。糟糕……我喜欢这里的简单。