Сортировка наблюдаемого массива в нокауте
У меня есть наблюдаемый массив в нокауте объектов человека. Я хотел уметь сортировать список лиц по фамилии. Проблема состоит в том, что в списке есть несколько дубликатов фамилий. В результате, когда имеется более одной фамилии, первые имена появляются по мере их нахождения. Я хотел бы иметь возможность сортировать массив по фамилии и, когда есть более одной фамилии, попробуйте также сортировать по имени. Я использую текстовый ввод для пользователя, чтобы начать вводить фамилию. Результаты привязаны к шаблону, который отображает все совпадения.
<input data-bind="value: filter, valueUpdate: 'afterkeydown'">
И вот мой фильтр фильтра для нокаута:
function Item(firstname, lastname) {
this.firstname = ko.observable(firstname);
this.lastname = ko.observable(lastname);
}
var playersViewModel = {
items: ko.observableArray([]),
filter: ko.observable("")
};
var players;
$(function() {
playersViewModel.filteredItems = ko.computed(function() {
var filter = this.filter().toLowerCase();
if (!filter) {
return this.items();
} else {
return ko.utils.arrayFilter(this.items(), function(item) {
return ko.utils.stringStartsWith(item.lastname().toLowerCase(), filter);
});
}
}, playersViewModel);
$.getJSON('./players.json', function(data) {
players = data.players;
playersViewModel.players = ko.observableArray(players);
ko.applyBindings(playersViewModel);
var mappedData = ko.utils.arrayMap(players, function(item) {
return new Item(item.firstname,item.lastname);
});
playersViewModel.items(mappedData);
});
});
Для фильтрации имени это прекрасно работает, но я не могу найти способ добавить в сортировку имя, когда есть дубликаты фамилий. Например, в моем массиве при сортировке по имени я получаю:
Joe Bailey
Jack Brown
Adam Brown
Bob Brown
Jim Byrd
Я хотел бы, чтобы имена повторяющихся имен также отсортировались по именам:
Joe Bailey
Adam Brown
Bob Brown
Jack Brown
Jim Byrd
Ответы
Ответ 1
Наблюдаемые массивы KnockoutJS предлагают функцию сортировки, поэтому относительно легко сортировать массив данных в вашем пользовательском интерфейсе (независимо от естественного порядка данных).
data-bind="foreach: items.sort(function (l, r) { return l.lastName() > r.lastName() ? 1 : -1 })"
Вам не нужно предварительно сортировать/повторно сортировать исходные данные, если вы сортируете до привязки (или перефилирования из-за сортировки), тогда вы делаете это неправильно.
Тем не менее, то, что вы просите, состоит в сортировке по двум значениям, фамилии, затем имени.
Вместо "l.lastName() > r.lastName()? 1: -1" рассмотрим следующее:
l.lastName() === r.lastName()
? l.firstName() > r.firstName() ? 1 : -1
: l.lastName() > r.lastName() ? 1 : -1
Это может быть более эффективным, я уверен. В принципе у вас есть три условных выражения:
- Являются ли последние имена равными?
- Если это так, сравните имена и верните результат.
- Повторите, сравните фамилии и верните результат.
Я просмотрел ваш код, и я не вижу такой функции сортировки.
Это похоже на ответ Майкла Наилучшего, однако я попытался разъяснить WHERE, чтобы обрабатывать сортировку (в вашем примере привязки, первый пример) и КАК достичь того вида, который вы ищете (несколько опорных точек).
data-bind="foreach: items().sort(function (l, r) { return (l.lastName() == r.lastName()) ? (l.firstName() > r.firstName() ? 1 : -1) : (l.lastName() > r.lastName() ? 1 : -1) })"
Естественно, это может стать громоздким, поскольку вы вводите больше векторов сортировки, таких как обратные или дополнительные данные, и поэтому вы должны реализовать функцию фильтра, которая выполняет вышеуказанную оценку для вас:
data-bind="foreach: items().sort(my.utils.compareItems)"
Ответ 2
Если вы убедитесь, что ваш players.json
возвращает отсортированные имена, все будет в порядке. Если он загружает их из базы данных, вам нужно добавить первое поле имени в предложение ORDER BY
.
Если вы хотите выполнить сортировку в Javascript, вы можете сделать это сразу после загрузки из службы:
players.sort(function(player1, player2) {
return player1.lastname.localeCompare(player2.lastname) ||
player1.firstname.localeCompare(player2.firstname);
});
Ответ 3
У меня возникли проблемы с сортировкой наблюдаемого массива, я не видел никаких результатов в моем коде.
Сначала вам нужно отсортировать результаты, полученные с помощью запроса ajax/getJSON, прежде чем вы вернете новые элементы в свой массив.
Таким образом, результаты сортируются до того, как они будут добавлены в ваш наблюдаемый массив в качестве новых элементов. Не нужно сортировать их при привязках.
См. пример ниже.
players(ko.utils.arrayMap(result, function (item) {
result.sort(function (l, r) {
return l.name == r.name ? 0 : (l.name < r.name ? -1 : 1);
});
return new Player(item);
}));
- получить данные с помощью AJAX/getJSON
- Сортировка результата запроса в выбранный вами массив
Ответ 4
Для этого нужно использовать два вида. В первой сортировке сортируйте по словам фамилии и во второй сортировке Сначала найдите по имени, если более двух человек имеют одинаковую фамилию, чем сортировать по первому имени в их местоположении, используя некоторый стандартный алгоритм сортировки....