2012-03-26 82 views
42

排序Backbone.js的集合,我可以成功地做到這一點。但我需要動態地完成這個排序。有時,我需要按照「firstName」來排序。正確的方式來對飛

我徹底的失敗者包括:

我想傳遞一個額外的變量指定變量sort()上。這沒有用。我也試過sortBy(),這也沒有工作。我嘗試將自己的函數傳遞給sort(),但是這也不起作用。將用戶定義的函數傳遞給sortBy()只是爲了讓結果沒有each方法,從而破壞了新分類的骨幹網集合點。

有人可以提供一個實際的例子排序通過一個變量,而不是硬編碼到比較函數?或者你有任何破解工作?如果沒有,請撥打sortBy()電話?

回答

36

有趣的問題。我會在這裏嘗試一個關於戰略模式的變體。您可以創建排序功能的哈希值,然後基於散列的選定成員上設置comparator

App.SomeCollection = Backbone.Collection.extend({ 
    comparator: strategies[selectedStrategy], 
    strategies: { 
     firstName: function() { /* first name sorting implementation here */ }, 
     lastName: function() { /* last name sorting implementation here */ }, 
    }, 
    selectedStrategy: "firstName" 
}); 

然後,你可以通過更新selectedStrategy屬性的值更改動態的排序策略。

編輯:我意識到我睡覺後:)這不會像我上面寫的那樣工作,因爲我們將對象字面值傳遞給Collection.extend。在創建對象時,comparator屬性將被評估一次,因此除非被迫這樣做,否則它不會隨時更改。有可能是一個更清潔的方式做到這一點,但是這證明了在飛行中切換比較功能:

var SomeCollection = Backbone.Collection.extend({ 
    comparator: function (property) { 
     return selectedStrategy.apply(myModel.get(property)); 
    }, 
    strategies: { 
     firstName: function (person) { return person.get("firstName"); }, 
     lastName: function (person) { return person.get("lastName"); }, 
    }, 
    changeSort: function (sortProperty) { 
     this.comparator = this.strategies[sortProperty]; 
    }, 
    initialize: function() { 
     this.changeSort("lastName"); 
     console.log(this.comparator); 
     this.changeSort("firstName"); 
     console.log(this.comparator);   
    }                       
}); 

var myCollection = new SomeCollection; 

這裏有一個jsFiddle演示這一點。

我認爲,所有問題的根源在於創建對象時立即評估JavaScript對象文字的屬性,因此如果要更改它,必須覆蓋該屬性。如果您嘗試寫入某種切換到屬性本身,它將被設置爲初始值並保持在那裏。

下面是一個很好的blog post,在略有不同的上下文中討論這個問題。

+0

謝謝。建議的實現和變體已經失敗,但我很感謝迴應:)。我想我在這裏錯過了一些非常小的東西。非常令人沮喪。我傾向於另一個我的javascript工作框架,考慮了我使用簡單的排序方式難度有多大。< – kikuchiyo 2012-03-26 04:59:44

+0

我即將自行解決此問題。我的應用程序顯示一個表。用戶將通過單擊表格中的列名稱來對錶格內容進行排序。我正在考慮讓桌面成爲一個擁有自己的「排序」模型的區域。該模型將跟蹤當前的「sortCriteria」。點擊列名將更新sortCriteria。我將在集合中有一個比較器功能。它只會從排序模型中獲取sortCriteria。 – 2014-07-16 17:34:36

+0

需要更新JSFiddles以使用服務器上存在的Underscore和Backbone。 cdnjs.com上的那些很好。 JSFiddle用來提供自己的,但我猜不再了。 我的初步評估有點苛刻,但我認爲'myModel'應該用傳遞給比較器的參數來替換,比較器應該是集合中的每個模型。 – 2016-03-06 19:21:04

12

所以,這是我的解決方案,實際工作。

App.Collection = Backbone.Collection.extend({ 

    model:App.Model, 

    initialize: function(){ 
     this.sortVar = 'firstName'; 
    }, 

    comparator: function(collection){ 
     var that = this; 
     return(collection.get(that.sortVar)); 
    } 

    }); 

然後在視圖中,我有米老鼠這樣的:

this.collections.sortVar = 'lastVar' 

this.collections.sort(this.comparator).each(function(){ 
    // All the stuff I want to do with the sorted collection... 
}); 

由於喬希·厄爾是連嘗試的解決方案是唯一一個和他領我在正確的方向,我接受他的回答。謝謝喬希:)

+1

感謝您的回答。 :)我更新了我原來的帖子 - 看看是否適合你。 – 2012-03-26 11:52:56

+0

如果您恰好在[Udacity的JavaScript設計模式](https://www.udacity.com/course/viewer#!/c-ud989/l-3525509902/m-3574768574)中進行練習,您必須在其中動態更改ToDo示例的排序順序,請注意,您必須調用'app.AppView'的'addAll'方法來重新添加新排序項目的列表。除了重新呈現視圖之外,還要檢查列表的填充方式。 [這是一個例子](https://github.com/enderandpeter/ud989-todo-app/blob/js-design-patterns/js/views/app-view.js#L119) – 2016-03-06 19:24:01

16

通過分配一個新的函數和調用排序來改變比較函數。

// Following example above do in the view: 

// Assign new comparator 
this.collection.comparator = function(model) { 
    return model.get('lastname'); 
} 

// Resort collection 
this.collection.sort(); 

// Sort differently 
this.collection.comparator = function(model) { 
    return model.get('age'); 
} 
this.collection.sort(); 
+0

這就是我一直也完成了。我在集合上使用了mixin,因此它可用於所有集合。我也觸發集合的重置,因爲我通常擁有需要更新的視圖。 – jhorback 2013-09-15 00:22:55

+0

非常簡單的答案。謝謝! – Trip 2015-01-07 10:10:39

+0

我可能會錯過一些東西,但這似乎是最好的解決方案。 – 2015-08-13 00:39:20

4

這是一個老問題,但我最近也有類似的需要(排序由用戶點擊事件中提供基於標準的集合),我想我會分享我爲別人解決這個問題的解決方案。不需要硬編碼的model.get('attribute')。

我基本上是用戴夫牛頓approach延長本地JavaScript陣列,並針對骨幹:

MyCollection = Backbone.Collection.extend({ 

    // Custom sorting function. 
    sortCollection : function(criteria) { 

     // Set your comparator function, pass the criteria. 
     this.comparator = this.criteriaComparator(criteria); 
     this.sort(); 
    }, 

    criteriaComparator : function(criteria, overloadParam) { 

     return function(a, b) { 
      var aSortVal = a.get(criteria); 
      var bSortVal = b.get(criteria); 

      // Whatever your sorting criteria. 
      if (aSortVal < bSortVal) { 
       return -1; 
      } 

      if (aSortVal > bSortVal) { 
       return 1; 
      } 

      else { 
       return 0; 
      } 

     }; 
    } 

}); 

注意「overloadParam」。根據documentation,Backbone使用Underscore的「sortBy」(如果您的比較器函數具有單個參數),如果它具有兩個參數,則使用原生JS風格的排序。我們需要後者,因此是「overloadParam」。

0

這就是我最終爲我正在開發的應用程序所做的事情。在我的收藏,我有:

comparator: function(model) { 
    var methodName = applicationStateModel.get("comparatorMethod"), 
     method = this[methodName]; 
    if (typeof(method === "function")) { 
     return method.call(null, model); 
    } 
} 

現在,我可以添加一些不同的方法來我的收藏:fooSort(),barSort(),和bazSort()。
我想foo​​Sort是默認的,所以我設置在我的狀態模型,如下所示:

var ApplicationState = Backbone.Model.extend({ 
    defaults: {    
     comparatorMethod: "fooSort" 
    } 
}); 

現在我所要做的就是寫在我看來,一個函數依賴於一個更新「comparatorMethod」的價值用戶點擊了什麼。我將集合設置爲偵聽這些更改並執行sort(),並將視圖設置爲偵聽排序事件並執行render()。

BAZINGA !!!!

3

看着source code,似乎有一個簡單的方法來做到這一點,將比較器設置爲字符串而不是函數。這工作,給定Backbone.Collection mycollection:

 mycollection.comparator = key; 
     mycollection.sort(); 
+0

但是,如果我們在集合中有空值,它將不起作用。 – Jyothu 2016-07-01 05:41:57