2012-02-16 63 views
2

我在更新服務器上的所有模型後刷新集合或更精確地收集視圖時出現問題。這裏是我的場景:Backbone Collection刷新所有項目

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

    });

所以我的問題是......我在成功上做了什麼:能夠分別刷新每個小模型,以便更新數字以適當的順序?也許某種_.each集合?或者,也許某種全局視圖刷新整個集合?

也是我的 成功:函數(數據) 將新訂單作爲列表(或JSON對象)從服務器返回。也許我可以重新使用這個命令來爲每個模型設置一個新的值,而不必在每次訂單改變時在服務器上進行不必要的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(); 
    }, 
+0

你能顯示你的視圖代碼嗎?具體來說,任何涉及到渲染集合,或與收集事件等工作。 – 2012-02-16 17:31:54

+0

@kpeel我更新了我的帖子,包括整個主視圖..現在應該更清楚.. – kernelpanic 2012-02-16 21:30:07

回答

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 
    */ 
} 
+1

感謝您的回答。我嘗試了你的建議,但我仍然對一件事感到困惑......應該重置什麼類型的數據(數據)?和新秩序陣列? JSON對象再次包含所有數據(我從fetch()獲得的一個對象?因爲/ reorder/url只用於重新排序服務器上的東西,而不是檢索集合。還更新了我的原始文章以包含主視圖代碼 – kernelpanic 2012-02-16 21:32:08

+0

最後,我用最簡單的解決方案去了解,我可以用試驗和錯誤的方法找到它,也許它不是最優雅的,但是對我來說很有用......(看我原來的帖子) – kernelpanic 2012-02-18 08:25:18

2

我覺得你的做法應該是在兩個單獨的步驟: 1)一方面你更新服務器 2)在另一方面上的數據更新集合客戶端

所以,你在第1步確定,你說它有效。

對於第2步,您可以利用事件驅動的編程。 的邏輯是這樣一個:

  1. 你只需要添加一個元件到集合(collection.add(模型)觸發一個「添加」事件)。
  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"); 
} 

,使項目得到ORD由位置客戶端ERED

**編輯* * 初始化功能修改。只使用集合中每個元素的「位置」屬性未更新的「排序」來使用提取,而不是「排序」。

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(); 
    }); 
+0

感謝您的回答。像一個非常有前途的,但每次我打電話排序,列表中的所有問題將重新排序回到原來的順序..所以我從來沒有得到它的工作:(我繼續了一個簡單的重置().. – kernelpanic 2012-02-18 08:22:09

+0

是的,你是對的,如果你剛剛重置,你應該在你的列表(集合)的每個元素(模型)中改變'位置'值,我編輯了答案,但仔細想想每次獲取項目是加法器,或者它是方便的o重新排序項目客戶端更新位置屬性。如果您有頻繁的插入,那麼流量會很高,並且等待時間(重新排列客戶端項目的速度會更快!)會變得無法忍受。如果其中一個答案能幫助你,請用「+1」或「正確」的答案加粗。謝謝。 – 2012-02-20 08:31:39