Backbone.js集合比较器按多个字段排序?

时间:2012-01-19 05:56:09

标签: javascript sorting backbone.js

  this.col = Backbone.Collection.extend({
    model: M,
    comparator: function(item) {
      return item.get("level");
    }
  });

以上代码按级别对项目进行排序。我想按级别排序,然后按标题排序。我能这样做吗?感谢。

5 个答案:

答案 0 :(得分:73)

@ amchang87的答案肯定有效,但我发现的另一个工作就是返回一个可排序字段的数组:

this.col = Backbone.Collection.extend({
    model: M,
    comparator: function(item) {
      return [item.get("level"), item.get("title")]
    }
});

我还没有在多个浏览器中对此进行测试,因为我认为它依赖于JS在数组的排序顺序中的行为(基于它们的内容)。它肯定适用于WebKit。

答案 1 :(得分:7)

字符串连接在按升序排序多个字段时工作正常,但它对我不起作用,因为1)我必须支持每个字段的asc / desc和2)某些字段是数字字段(即,我想要10到如果是提升,请来2。)所以,下面是我使用的比较器功能,可以满足我的需求。它假设主干集合具有一个赋值为'sortConfig'的变量,该变量是一个带有字段名称和排序顺序方向的JSON对象数组。例如,

{
    "sort" : [
        {
            "field": "strField",
            "order": "asc"
         },
         {
             "field": "numField",
             "order": "desc"
         },
         ...
     ]
}

上面的JSON对象被指定为集合的'sortConfig',下面的函数将首先按strField按升序排序Backbone,然后按降序排序按numField排序等。如果没有指定排序顺序,则排序默认升序。

multiFieldComparator: function(one, another) {
    // 'this' here is Backbone Collection
    if (this.sortConfig) {
        for (var i = 0; i < this.sortConfig.length; i++) {
            if (one.get(this.sortConfig[i].field) > another.get(this.sortConfig[i].field)) {
                return ("desc" != this.sortConfig[i].order) ? 1 : -1;
            } else if (one.get(this.sortConfig[i].field) == another.get(this.sortConfig[i].field)) {
                // do nothing but let the loop move further for next layer comparison
            } else {
                return ("desc" != this.sortConfig[i].order) ? -1 : 1;
            }
        }
    }
    // if we exited out of loop without prematurely returning, the 2 items being
    // compared are identical in terms of sortConfig, so return 0
    // Or, if it didn't get into the if block due to no 'sortConfig', return 0
    // and let the original order not change.
    return 0;
}

答案 2 :(得分:2)

如果您需要对降序进行排序以及某些升序......返回数组不一致...

我创建了一小组函数,可用于将相关的比较整数返回给Backbone Comparator函数:

backbone-collection-multisort

答案 3 :(得分:1)

主要的是Backbone按一个项目的相对值排序到另一个项目。因此,在单个集合中排序两次并不是直接可行的,但我会尝试这样做。

this.col = Backbone.Collection.extend({
    model: M,
    comparator: function(item) {
      // make sure this returns a string!
      return item.get("level") + item.get("title");
    }
});

这样做会返回一串像“1Cool”,“1title”,“2newTitle”...... Javascript应首先按数字字符对字符串进行排序,然后对每个字符进行排序。但只有您的等级具有相同的位数时,这才会起作用。 IE“001title”vs“200title”。但主要的想法是你需要生成两个可比较的对象,排成一个数字或字符串,可以根据一个标准相互比较。

其他解决方案是使用下划线“groupby”您的级别,然后使用“sortby”手动排序每个级别组,然后使用这个新创建的数组手动替换底层集合。每当集合“更改”时,您可以设置一个函数来执行此操作。

答案 4 :(得分:0)

在hyong的回答中“启发”了。

这也允许你在比较之前更改数据,valueTransforms是一个对象,如果该对象中有一个具有函数的属性,它将被使用。

    /*
     * @param {Object} sortOrders ie: 
     * {
     *     "description": "asc",
     *     "duedate": "desc",
     * }
     * @param {Object} valueTransforms
     */
    setMultiFieldComparator: function(sortOrders, valueTransforms) {
        var newSortOrders = {}, added = 0;
        _.each(sortOrders, function(sortOrder, sortField) {
            if (["asc", "desc"].indexOf(sortOrder) !== -1) {
                newSortOrders[sortField] = sortOrder;
                added += 1;
            }
        });
        if (added) {
            this.comparator = this._multiFieldComparator
                .bind(this, newSortOrders, valueTransforms || this.model.prototype.valueTransforms || {});
        } else {
            this.comparator = null;
        }
    },

    _multiFieldComparator: function(sortOrders, valueTransforms, one, another) {
        var retVal = 0;
        if (sortOrders) {
            _.every(sortOrders, function(sortOrder, sortField) {
                var oneValue = one.get(sortField),
                    anotherValue = another.get(sortField);
                if (valueTransforms[sortField] instanceof Function) {
                    oneValue = valueTransforms[sortField](oneValue);
                    anotherValue = valueTransforms[sortField](anotherValue);
                }
                if (oneValue > anotherValue) {
                    retVal = ("desc" !== sortOrder) ? 1 : -1;
                } else if (oneValue < anotherValue) {
                    retVal = ("desc" !== sortOrder) ? -1 : 1;
                } else {
                    //continue
                    return true;
                }
            });
        }
        return retVal;
    },