Подтвердить что ты не робот

Правильный способ сортировки коллекции backbone.js на лету

Я могу это сделать:

App.SomeCollection = Backbone.Collection.extend({
  comparator: function( collection ){
    return( collection.get( 'lastName' ) );
  }
});

Хорошо, если я хочу иметь коллекцию, которая сортируется только по 'lastName'. Но мне нужно, чтобы эта сортировка выполнялась динамически. Иногда мне нужно отсортировать, скажем, "firstName".

Мое полное отсутствие:

Я попытался передать дополнительную переменную, указав переменную на sort() on. Это не сработало. Я также пробовал sortBy(), который тоже не работал. Я попытался передать свою собственную функцию sort(), но это тоже не сработало. Передача определяемой пользователем функции в sortBy() только для того, чтобы результат не имел метода each, победив точку с новой сортированной базой данных.

Может ли кто-нибудь предоставить практический пример сортировки переменной, которая не является жестко закодированной в функции компаратора? Или любой хак, который у вас есть, работает? Если нет, рабочий вызов sortBy()?

4b9b3361

Ответ 1

Интересный вопрос. Я бы попробовал вариант на схеме стратегии здесь. Вы можете создать хеш функций сортировки, а затем установить 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.

EDIT: после того, как я лег спать, я понял, что это не будет работать так, как я написал выше, потому что мы передаем объектный литерал 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 оцениваются сразу же после создания объекта, поэтому вам нужно перезаписать свойство, если вы хотите его изменить. Если вы попытаетесь написать какое-то переключение в свойство, оно будет установлено на начальное значение и останется там.

Здесь хороший пост в блоге, который обсуждает это в немного другом контексте.

Ответ 2

Измените функцию компаратора, назначив ей новую функцию и вызовите сортировку.

// 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();

Ответ 3

Итак, это было мое решение, которое действительно сработало.

  App.Collection = Backbone.Collection.extend({

    model:App.Model,

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

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

  });

Тогда в представлении я должен M-I-C-K-E-Y M-O-U-S-E это так:

this.collections.sortVar = 'lastVar'

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

Поскольку Джош Эрл был единственным, кто даже попытался решить проблему, и он вел меня в правильном направлении, я принимаю его ответ. Спасибо Josh:)

Ответ 4

Это старый вопрос, но у меня возникла аналогичная потребность (сортируйте коллекцию на основе критериев, которые будут предоставлены событием клика пользователя), и подумал, что я поделюсь своим решением для других, занимающихся этой проблемой. Не требуется hardcoded model.get('attribute').

В основном я использовал подход Dave Newton для расширения собственных JavaScript-массивов и адаптировал его к Backbone:

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". В документации, Backbone использует Underscore "sortBy", если ваша функция компаратора имеет один параметр и собственный тип JS-стиля, если он имеет два Титулы. Нам нужен последний, следовательно, "перегруженный парам".

Ответ 5

Глядя на исходный код, кажется, что есть простой способ сделать это, установив компаратор в строку вместо функции. Это работает, учитывая Backbone.Collection mycollection:

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

Ответ 6

Вот что я сделал для приложения, над которым я сейчас работаю. В моей коллекции я:

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

Теперь я могу добавить несколько разных методов в свою коллекцию: fooSort(), barSort() и bazSort().
Я хочу, чтобы fooSort был по умолчанию, поэтому я установил его в моей модели состояния следующим образом:

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

Теперь все, что мне нужно сделать, это написать функцию в моем представлении, которая обновляет значение "comparatorMethod" в зависимости от того, что пользователь нажимает. Я установил коллекцию для прослушивания этих изменений и выполнил sort(), и я установил представление для прослушивания событий сортировки и выполнил render().

Bazinga!!!!