Backbone.js коллекции компараторов сортировать по нескольким полям? - PullRequest
42 голосов
/ 19 января 2012
  this.col = Backbone.Collection.extend({
    model: M,
    comparator: function(item) {
      return item.get("level");
    }
  });

Данный код сортирует элементы по уровням. Я хочу отсортировать по уровню, а затем по названию. Могу ли я сделать это? Благодаря.

Ответы [ 5 ]

73 голосов
/ 10 мая 2012

@ amchang87 ответ определенно работает, но другой, который я нашел сработавшим, просто возвращает массив сортируемых полей:

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

Я еще не проверял это в нескольких браузерах, так как думаю, что он основанПоведение JS в порядке сортировки для массивов (на основе их содержимого).Это определенно работает в WebKit.

7 голосов
/ 04 октября 2013

Конкатенация строк работает нормально при сортировке нескольких полей в порядке возрастания, но у меня это не сработало, потому что 1) мне приходилось поддерживать asc / desc для каждого поля и 2) некоторые поля были числовыми полями (т. Е. Я хочу, чтобы 10 кприходите после 2, если он поднимается).Итак, ниже была функция сравнения, которую я использовал и работал нормально для моих нужд.Предполагается, что базовая коллекция имеет переменную, назначенную с помощью sortConfig, который представляет собой массив объектов JSON с именем поля и направлением сортировки.Например,

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

С указанным выше объектом JSON, назначенным для коллекции как sortConfig, функция ниже будет сначала выполнять сортировку Backbone по strField в порядке возрастания, а затем сортировать по 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 голосов
/ 15 октября 2013

Возвращение массива не согласовано, если вам нужно отсортировать по убыванию и по возрастанию ...

Я создал небольшой набор функций, которые можно использовать для возврата соответствующего целого числа сравнения обратно в функцию Backbone Comparator:

магистральная коллекция-мультисортировка

1 голос
/ 19 января 2012

Главное, что 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" против "200title". Однако основная идея заключается в том, что вам нужно создать два сопоставимых объекта - строку или число, которые можно сравнивать друг с другом на основе одного критерия.

Другим решением было бы использовать подчеркивание для «группировки» вашего уровня, затем использовать «сортировку» для ручной сортировки каждой группы уровней, а затем вручную заменять базовую коллекцию этим вновь созданным массивом. Вероятно, вы можете настроить функцию, чтобы делать это всякий раз, когда коллекция «меняется».

0 голосов
/ 20 октября 2013

"Вдохновленный" в ответе 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;
    },
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...