【问题标题】:Backbone Collection refresh all itemsBackbone Collection 刷新所有项目
【发布时间】:2014-12-01 15:32:32
【问题描述】:

更新服务器上的所有模型后,我在刷新集合或更准确的集合视图时遇到问题。这是我的场景:

  1. 我从服务器获取了一组问题。每个问题都有一个位置属性,因此我可以操纵列表中的顺序并以适当的顺序将其保存回服务器。

  2. 我有一个用于每个列表项的视图和一个具有更全局范围的视图,它生成每个列表项并更新集合。基本上,我使用的是 O'Reilly 书籍“Javascript Web 应用程序”中的一个示例,该示例与此处发现的著名 Todo 注释教程非常相似:http://documentcloud.github.com/backbone/docs/todos.html 所以除了一些定制模型外,结构几乎相同。一切正常。

  3. 但是,我在更新集合时遇到了问题,我重新排序了 我的全局视图中有一个方法,每当我在列表中拖动列表项时都会触发该方法。顺便说一句,它运行良好并更新了服务器上项目的顺序,但我也希望能够更新列表中每个项目的数字。

    window.QuestionView = Backbone.View.extend({
    
    el: $("#content"),
    events : {
        'sortupdate ol#questions': 'sortStuff'
    },
    
    initialize: function(collection) {
        this.collection = new QuestionsList;
    
        _.bindAll(this, 'addOne', 'addAll', 'render', 'addNewItem', 'addItem');
        this.collection.bind('add', this.addNewItem);
        this.collection.bind('all', this.render);
        this.collection.bind('reset', this.addAll);
        this.collection.fetch({
            data: { quiz_id: $qid },
            processData:true
        });
    },
    
    render: function() {},
    
    sortStuff: function() {
    
        $this = this;
        $.ajax({
            url: "/hq/reorder/",
            type: "POST",
            data: $("#questions").sortable("serialize")+"&id="+$qid,
            dataType: 'json',
            success: function(data) {
    
            }
        });
    },
    
    addItem: function() {
        this.collection.add({title: 'New title goes here'});
        return false;
    },
    
    addNewItem: function(question) {
        var view = new ItemView({model: question, parent: this});
        var element = view.render().el;
        this.$("#questions").prepend(element);
        $that = this;
        $(view.render().el).addClass('new');
    },
    
    addOne: function(question) {
      var view = new ItemView({model: question, parent: this});
      this.$("#questions").prepend(view.render().el);
    },
    
    addAll: function() {
      this.collection.each(this.addOne);
      return false;
    }
    

    });

所以我的问题是..我该怎么做才能成功:能够分别刷新每个小模型,以便将数字更新为正确的顺序?也许某种 _.each 在 Collection 上?或者也许对整个集合进行某种全局视图刷新?

也是我的 成功:函数(数据) 从服务器返回新订单作为列表(或 JSON 对象)。也许我可以重用这个订单来为每个模型设置一个新值,而无需在每次更改订单时在服务器上进行不必要的 fetch() 调用?

编辑:

我终于设法让它与重置一起工作,清除视图并重新获取新集合。也许这不是最好的方法,因为有一个额外的调用服务器与 fetch()..

 sortStuff: function() {

        $this = this;
        $.ajax({
            url: "/hq/reorder/",
            type: "POST",
            data: $("#questions").sortable("serialize")+"&id="+$qid,
            dataType: 'json',
            success: function(data) {
                $this.rerender();
            }
        });


    },

    rerender: function() {

        this.collection.fetch({
            data: { quiz_id: $qid },
            processData:true
        });
        $("#questions").html("");
        this.collection.reset();
        this.addAll();
    },

【问题讨论】:

  • 你能显示你的视图代码吗?特别是与呈现集合或使用集合事件等相关的任何内容。
  • @kpeel 我更新了我的帖子以包含整个主视图..现在应该更清楚了..

标签: javascript backbone.js jquery-ui-sortable


【解决方案1】:

我认为您的方法应该分两个单独的步骤: 1)一方面你更新服务器上的数据 2) 另一方面,您更新集合 client-side

所以,你在第 1 步没问题,你说它有效。

对于第 2 步,您可以利用事件驱动编程。 逻辑是这样的:

  1. 您只需向集合中添加一个元素(collection.add(model) 会触发“添加”事件)。
  2. 在集合中,您侦听“添加”事件。当你捕捉到它时,你会再次对你的集合进行排序(collection.sort 会触发一个“重置”事件)
  3. 在您的列表视图(在您的情况下为 questionView)中,您侦听集合重置事件,一旦触发,您将重新呈现您的视图

示例代码:

1) QuestionView:addItem 已移除,addNewItem 已简化(不得渲染)

 window.QuestionView = Backbone.View.extend({
 el: $("#content"),
 events : {
     'sortupdate ol#questions': 'sortStuff'
 },

 initialize: function(collection) {
     this.collection = new QuestionsList;
     _.bindAll(this, 'addOne', 'addAll', 'addNewItem');
     this.collection.bind('add', this.addNewItem);
     this.collection.bind('reset', this.addAll);
     this.collection.fetch({
     data: { quiz_id: $qid },
     processData:true
     });
 },

 render: function() {},

 sortStuff: function() {

     $this = this;
     $.ajax({
         url: "/hq/reorder/",
         type: "POST",
         data: $("#questions").sortable("serialize")+"&id="+$qid,
         dataType: 'json',
         success: function(data) {

         }
     });
 },

 //METHOD addItem REMOVED!!!


 addNewItem: function(question) {
     this.collection.add({title: 'New title goes here'}); //***IT FIRES AN ADD EVENT
     },

 addOne: function(question) {
   var view = new ItemView({model: question, parent: this});
   this.$("#questions").prepend(view.render().el);
 },

 addAll: function() {
   this.collection.each(this.addOne);
   return false;
 }

});

2) 集合捕获添加事件并排序(触发“重置”事件) 你可以一直在 QuestionView 中处理它,你的初始化函数就变成了。

 initialize: function(collection) {
     this.collection = new QuestionsList;
     _.bindAll(this, 'addOne', 'addAll', 'addNewItem');
     this.collection.bind('add', this.addNewItem);
     this.collection.bind('reset', this.addAll);
     this.collection.fetch({
     data: { quiz_id: $qid },
     processData:true
     });
     //ADD THIS*****
     this.collection.on('add', function(){
         this.collection.sort();
     });
 },

3)第三步已经完成,你只需重新渲染视图

最好的办法是对集合中的元素进行排序,定义一个新的“比较器”函数,该函数使用列表的“位置”属性

类似(在 QuestionView 中)

this.collection.comparator: function(){
   return this.collection.get("position");
}

以便项目按位置排序CLIENT SIDE

**编辑** 初始化函数已修改。使用 Fetch 代替 'sort',只要集合中每个元素的 'position' 属性不更新,这是没有用的。

 initialize: function(collection) {
     this.collection = new QuestionsList;
     _.bindAll(this, 'addOne', 'addAll', 'addNewItem');
     this.collection.bind('add', this.addNewItem);
     this.collection.bind('reset', this.addAll);
     this.collection.fetch({
     data: { quiz_id: $qid },
     processData:true
     });
     //ADD THIS*****
     this.collection.on('add', function(){
         this.collection.fetch();
     });

【讨论】:

  • 感谢您的回答。你的方法看起来很有前途,但是每次我调用 sort 时,列表中的所有问题都会重新排序回原来的顺序。所以我从来没有让它工作:(我继续使用简单的 reset() ..
  • 是的,你是对的。如果您只是重置,您应该更改列表(集合)的每个元素(模型)中的“位置”值。我编辑了答案。但是,请仔细考虑是否最好在每次添加项目时获取,或者在客户端重新排序项目更新位置属性更方便。如果您经常插入,那么流量会很高,并且等待时间(在客户端重新排序项目更快!)可能会变得难以忍受。如果您得到的答案之一对您有所帮助,请用“+1”或“正确”答案加粗。谢谢。
【解决方案2】:

你应该做Questions.reset(data);,但是你需要告诉ajax响应是json:

sortStuff: function() {
   $.ajax({
     url: '/order',
     data: $("ol#questions").sortable('serialize'),
     dataType: 'json',
     success: function(data) {
        // now data is an object
        Questions.reset(data);
     });
   });
}

我希望你已经知道主干是事件驱动的,并且你有一个集合重置事件绑定到渲染方法,所以这里不需要显式调用渲染。

编辑:

好的,现在通过代码,我看到了您要完成的工作,但您的逻辑有缺陷。您不应该等待 ajax 调用返回新订单。最好在客户端更新订单,然后保存模型。

这是一个 jsfiddle 示例:http://jsfiddle.net/b75px/

将其与骨干相结合,您应该拥有:

注意,我只是在猜测您是如何组织这些问题的。如果您有任何其他问题,请更新您的问题并提供更多详细信息。

events: {
    'sortstart ol#questions': 'startSortingQuestions',
    'sortupdate ol#questions': 'updateQuestions'
},
startSortingQuestions: function(event, ui) {
    this.beforeIndex = ui.item.index();
},
updateQuestions: function(event, ui) {
    var before = this.beforeIndex,
        after = ui.item.index();

    // now that you have the index change, all you have to do is set the new index
    // and save them to the database
    this.collection.at(before).set({ index: after; }).save();
    this.collection.at(after).set({ index: before; }).save();

    // passing silent: true because sort invokes the reset event,
    // and we don't need to redraw anything
    this.collection.sort({ silent: true });

    /* or maybe an even better approach: 
    var beforeModel = this.collection.at(before);
    var toSwapModel = this.collection.at(after);

    this.collection.remove(beforeModel);
    this.collection.remove(toSwapModel);
    this.collection.add(beforeModel, { at: after, silent: true });
    this.collection.add(toSwapModel, { at: before, silent: true });

    note that I have no idea on how your database is structured, so my guess is
    every question has it's index so you know it's order
    therefore, you should still update the model's index field or whatever it is you're doing
    */
}

【讨论】:

  • 感谢您的回答。我尝试了您的建议,但我仍然对一件事感到困惑..应该重置什么样的(数据)?和新订单数组?再次包含所有数据的 JSON 对象(我从 fetch() 获得的那个?因为 /reorder/ url 仅用于重新排序服务器上的内容,而不是检索集合。我还更新了我的原始帖子以包含主视图代码.
  • 最后,我采用了通过反复试验可以找到的最简单的解决方案。也许它不是最优雅的,但对我有用..(看我原来的帖子)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-07
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
相关资源
最近更新 更多