簡體   English   中英

對骨干集合進行排序

[英]Sorting Backbone Collections

所需的功能

我正在使用Backbone.Collection來查看可排序列表中的數據。 我已經找到了部分,點擊某些dom元素設置我的Collection上的屬性,以確定我想要排序的字段,以及應該進行排序的方向。 然后應在集合上觸發排序,之后視圖將更新。

最終我希望能夠對數字字段以及字符串進行排序。 某些字符串應按字母順序排序,其他字符串按自定義預定義順序

我目前的做法

我在反向排序字符串上發現了以下帖子: 使用backbone.js以相反的順序對字符串進行排序

我試圖將它與比較器函數和以下自定義屬性結合起來:

  1. “狀態”字段中可能值的自定義排序順序
  2. 哪個字段應該用於排序
  3. 排序的方向

到目前為止我收集的Collection和Model類:

收藏

var ApplicationCollection = Backbone.Collection.extend({
  model: ApplicationModel,
  url: 'rest/applications',

  // sorting
  statusOrder: ['new', 'to_pay', 'payed', 'ready'],
  sortField: 'submission_timestamp',
  sortOrder: 'asc',
  sortBy: function() {
    console.log('ApplicationCollection.sortBy', this, arguments);
    console.log('this.comparator', this.comparator);
    var models = _.sortBy(this.models, this.comparator);
    if (this.sortOrder != 'asc') {
      models.reverse();
    }
    return models;
  },
  comparator: function(application) {
    console.log('ApplicationCollection.comparator', this, arguments);
    switch(this.sortField) {
      case 'status':
        return _.indexOf(this.statusOrder, application.get(this.sortField));
        break;
      case 'submission_timestamp':
      default:
        return application.get(this.sortField)
        break;
    }
  }
});

該模型

var ApplicationModel = Backbone.Model.extend({
  defaults: {
    'drupal_id': 0,
    'language': '',
    'last_name': '',
    'first_name': '',
    'address': '',
    'zip_code': '',
    'city': '',
    'country': '',
    'telephone': '',
    'cell_phone': '',
    'email': '',
    'date_of_birth': '',
    'email': '',
    'date_of_birth': '',
    'pilot_training_institute': '',
    'date_of_exam': '',
    'flight_hours_total': '',
    'date_of_last_flight': '',
    'date_of_mcc_certificate': '',
    'date_of_ir_renewel': '',
    'package': '',
    'submission_timestamp': '',
    'status': 'new'
  },
  urlRoot: 'rest/applications'
});

當前(不希望的)結果

我有一個存儲在'pendingApplications'中的集合實例,如下所示:

var pendingApplications = new ApplicationCollection();
pendingApplications.fetch();

這將從服務器加載應用程序,並且所有應用程序按計划運行 我可以使用應用程序列表呈現視圖,模型上有所有屬性等。

要對集合進行排序,請執行以下操作:

pendingApplications.sortOrder = 'asc';
pendingApplications.sortField = 'current_timestamp'; // format: YYYY-mm-dd HH:mm:ss
pendingApplications.sort();

這會觸發Collection上的sort函數。 控制台告訴我'ApplicationCollection.sortBy'方法在'pendingApplications'實例的范圍內執行,這是預期的。

但是,'ApplicationCollection.comparator'方法在全局范圍內執行,我不知道為什么。 此外,比較器方法的參數都沒有包含'pendingApplications'實例。

我想要的是我的比較器方法在'pendingApplications'實例的范圍內執行,或者至少我希望能夠以某種方式能夠訪問'pendingApplications'實例上的屬性。

范圍問題? 錯誤的做法? 歡迎任何建議......

有誰知道如何解決這個問題? 或者我是以錯誤的方式解決這個問題,是否有另一種解決方案可以在Backbone.Collection上任意定義自定義排序?

解決方案

我最終實現了一個排序功能作為Backbone.Collection的裝飾器。 這樣做的原因是因為我還有一個裝飾器來過濾集合中的項目。 通過使用排序裝飾器,我可以將排序應用於過濾的子項集,這可能更快。

/**
 * returns a new Backbone.Collection which represents a sorted version of the
 * data contained within the original Backbone.Collection.
 *
 * @param {Backbone.Collection} original
 */
SortedCollection: function(original, criteria) {
  var sorted = new original.constructor(),

  // sensible defaults
  defaultSortCriteria = {
    custom: {},
    field: 'id',
    direction: 'asc'
  };

  // configuration
  sorted.sortCriteria = _.extend(defaultSortCriteria, criteria);

  // do the stuff
  sorted.comparator = function(a, b) {
    // @formatter:off
    var criteria = this.sortCriteria,
        custom, 
        field = criteria.field,
        direction = criteria.direction,
        valA,
        valB;
        // @formatter:on

    // custom sort
    if (_.has(criteria.custom, field)) {
      custom = criteria.custom[field];

      // custom param is a comparator itself.
      if (_.isFunction(custom)) {
        return custom(a, b);
      }
      // custom param is an example of a sorted array.
      else if (_.isArray(custom)) {
        valA = _.indexOf(custom, a.get(field));
        valB = _.indexOf(custom, b.get(field));
      }
      else {
        throw new Error('Invalid custom sorting criterium.');
      }
    }
    // nothing custom here, use the field value directly.
    else {
      valA = a.get(field);
      valB = b.get(field);
    }

    // compare that shizzle!
    if (valA > valB) {
      return (direction == 'desc') ? -1 : 1;
    }
    if (valA < valB) {
      return (direction == 'desc') ? 1 : -1;
    }
    else {
      if (a.get('id') > b.get('id')) {
        return (direction == 'desc') ? -1 : 1;
      }
      else if (a.get('id') < b.get('id')) {
        return (direction == 'desc') ? 1 : -1;
      }
      else {
        return 0;
      }
    }
  };

  // update collection if original changes
  original.on("add", function(model) {
    sorted.add(model);
  });
  original.on("reset", function() {
    sorted.reset(original.models);
  });
  original.on("remove", function(model) {
    sorted.remove(model);
  });

  return sorted;
}

裝飾者的用法:

original = new ApplicationsCollection();
sortable = SortedCollection(original);
sortable.sortCriteria = { 
  sortField: 'submission_timestamp',
  sortDirection: 'desc'
}
sortable.sort();

上面的代碼片段執行以下操作:

  • 實例化一個新的ApplicationsCollection;
  • 實例化可排序集合,該集合擴展原始集合並偵聽原始集合上的相關事件。
  • 告訴Sortable Collection按'submission_timestamp'屬性按降序排序。
  • 對Sortable Collection進行排序。

當新模型添加到原始集合或從原始集合中刪除時,或者在重置原始集合時,新的可排序集合也會自動保持排序。

默認情況下, comparator()函數在集合的范圍內調用,至少在最新版本的Backbone中。

我懷疑你可能通過定義sortBy()函數來破壞它。 該函數已由Backbone定義,並且在某些情況下由Backbone的sort()函數在內部使用。 嘗試刪除該功能,看看它是否按預期工作。

您似乎只是使用sortBy()來反轉排序順序。 這可以在comparator()函數中通過在適當時將返回值乘以-1來實現。

根據其他答案,修改sortBy方法以調用原始Collection.sortBy方法,如下所示:

sortBy: function(){
  var models = Backbone.Collection.prototype.sortBy.apply(this, arguments);
  if (this.sortOrder != 'asc') {
    models.reverse();
  }
  return models;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM