Правильный способ сортировки коллекции backbone.js на лету
Я могу это сделать:
App.SomeCollection = Backbone.Collection.extend({
comparator: function( collection ){
return( collection.get( 'lastName' ) );
}
});
Хорошо, если я хочу иметь коллекцию, которая сортируется только по 'lastName'. Но мне нужно, чтобы эта сортировка выполнялась динамически. Иногда мне нужно отсортировать, скажем, "firstName".
Мое полное отсутствие:
Я попытался передать дополнительную переменную, указав переменную на sort()
on. Это не сработало. Я также пробовал sortBy()
, который тоже не работал. Я попытался передать свою собственную функцию sort(), но это тоже не сработало. Передача определяемой пользователем функции в sortBy()
только для того, чтобы результат не имел метода each
, победив точку с новой сортированной базой данных.
Может ли кто-нибудь предоставить практический пример сортировки переменной, которая не является жестко закодированной в функции компаратора? Или любой хак, который у вас есть, работает? Если нет, рабочий вызов sortBy()
?
Ответы
Ответ 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!!!!