Backbone Collection刷新所有项目

时间:2012-02-16 10:46:41

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

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

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

  2. 我有一个视图用于每个单个列表项和一个具有更全局范围的视图,该视图生成每个列表项并更新集合。基本上我使用的是O'Reilly的书“Javascript Web Applications”中的一个例子,它类似于在这里找到的着名的Todo注释教程: http://documentcloud.github.com/backbone/docs/todos.html 因此除了一些定制模型外,结构几乎完全相同。 Everythings工作正常。

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

    });

  4. 所以我的问题是..我在成功时做了什么:能够分别刷新每个小模型,以便将数字更新为正确的顺序?也许某种_.each on 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();
        },
    

2 个答案:

答案 0 :(得分:2)

我认为您的方法应分两个步骤: 1)一方面,您更新服务器上的数据 2)另一方面,您更新集合客户端

所以,你在第1步就可以了,你说它有效。

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

  1. 你只需要将一个元素添加到集合中(collection.add(model)会触发'add'事件)。
  2. 在集合中,您可以收听“添加”事件。当你抓住它时,你再次对你的集合进行排序(collection.sort触发'重置'事件)
  3. 在列表视图(在您的情况下为questionView)中,您将侦听集合重置事件,并在触发后重新呈现视图
  4. 示例代码:

    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)第三步已经完成,你只需重新渲染视图

    最好的是你在集合中对元素进行排序,定义一个新的'比较'功能,它使用列表的'position'属性

    类似(在QuestionView中)

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

    以便按位置客户端

    排序商品

    **编辑* * 初始化函数已修改。使用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();
         });
    

答案 1 :(得分:0)

你应该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);
     });
   });
}

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

编辑:

好的,现在有了代码,我看到你要完成的任务,你的逻辑是有缺陷的。您不应该等待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
    */
}