Угловой порядокПо номеру сортировка как текст в ng-repeat

У меня есть эти данные:

[{"id":"42","firstname":"Sarah","lastname":"Dilby","age":"40","cars":"Yaris"},
{"firstname":"Jason","lastname":"Diry","age":"5","id":"5"},
{"id":"6","firstname":"Bilson","lastname":"Berby","age":"1","cars":"Tipo"}]

Когда я заказываю по идентификатору или по возрасту в ng-repeat, он сортирует число как текст. Поскольку я нигде не могу найти написанного о том, что это проблема, я предполагаю, что проблема связана с моим кодом. Я создал эту скрипту: http://jsfiddle.net/vsbGH/1/ Извините за шаблон, но jsfiddle не t разрешить в поле html. Во всяком случае, это код, который загружает и сортирует данные:

//user data
app.service('People', function() {
var People = {};
People.details = [{"id":"42","firstname":"Sarah","lastname":"Dilby","age":"40","cars":"Yaris"},
                  {"firstname":"Jason","lastname":"Diry","age":"5","id":"5"},
                  {"id":"6","firstname":"Bilson","lastname":"Berby","age":"1","cars":"Tipo"}]
return People;
});

//list ctrl
controllers.listCtrl = function ($scope,People) {
 $scope.people = People.details;

 $scope.sortList = function(sortname) {
    $scope.sorter = sortname;
 }
}

И это часть шаблона ng-repeat:

<tr ng-repeat="person in people | orderBy:sorter ">
        <td>{{person.id | number}}</td>
        <td>{{person.firstname}} </td>
        <td>{{person.lastname}} </td>
        <td>{{person.age | number}}</td>
        <td>{{person.cars}} </td>
 </tr>

Большое спасибо, если вы можете помочь мне понять, почему числовые данные не сортируются как числа, а почему они сортируются как текст.


person dewd    schedule 26.05.2013    source источник


Ответы (7)


Я думаю, что наиболее подходящим решением является правильное форматирование чисел, которые у меня есть в моих объектах JSON, то есть не заключать их в кавычки. Так:

 [{"id":"42","firstname":"Sarah","lastname":"Dilby","age":"40","cars":"Yaris"},
  {"firstname":"Jason","lastname":"Diry","age":"5","id":"5"},
  {"id":"6","firstname":"Bilson","lastname":"Berby","age":"1","cars":"Tipo"}]

становится:

[{"id":42,"firstname":"Sarah","lastname":"Dilby","age":40,"cars":"Yaris"},
 {"firstname":"Jason","lastname":"Diry","age":5,"id":5},
 {"id":6,"firstname":"Bilson","lastname":"Berby","age":1,"cars":"Tipo"}]

Я предполагаю, что решение SergL хорошо, если невозможно исправить формат данных JSON.

Чтобы добавить к этому, проблема в моем конкретном случае связана с функцией PHP json_encode на стороне сервера. По умолчанию он обрабатывает числа как строки. Чтобы исправить это, мне пришлось добавить параметр JSON_NUMERIC_CHECK к методу encode в PHP-скрипте:

json_encode($assoc_array,JSON_NUMERIC_CHECK);
person dewd    schedule 27.05.2013
comment
Мне просто нужно было сделать JSON_NUMERIC_CHECK сегодня. Хороший. - person Cory Collier; 04.12.2013
comment
Я использовал JSON_NUMERIC_CHECK в первый раз, и это просто потрясающе. - person RN Kushwaha; 27.02.2015
comment
JSON_NUMERIC_CHECK просто великолепен. Это сработало как шарм, спасибо @dewd! - person jordan; 04.10.2015
comment
К вашему сведению, JSON_NUMERIC_CHECK тоже может сломаться. Он удаляет лидирующие нули. например. номер телефона 0401231234 становится 401231234. - person Firze; 22.11.2017
comment
@Firze Я никогда не рассматриваю номер телефона как число, он всегда должен оставаться строкой. - person Amir Savand; 16.08.2018
comment
Этот пост продолжает давать результаты даже спустя 5 лет. JSON_NUMERIC_CHECK для победы. - person Creative Links; 21.01.2019

Вам не нужно изменять свой JSON. Вы можете передать функцию фильтру orderBy следующим образом:

$scope.sorterFunc = function(person){
    return parseInt(person.id);
};

<tr ng-repeat="person in people | orderBy:sorterFunc ">
        <td>{{person.id | number}}</td>
        <td>{{person.firstname}} </td>
        <td>{{person.lastname}} </td>
        <td>{{person.age | number}}</td>
        <td>{{person.cars}} </td>
 </tr>
person Ragnar    schedule 29.04.2016
comment
как сделать заказ по убыванию? - person Biswas Khayargoli; 12.05.2017
comment
Чтобы упорядочить по убыванию, вы можете добавить - перед parseInt(): return - (parseInt(person.id)); или еще лучше, вы можете добавить параметр sorterFunc, чтобы указать тип сортировки ASC или DESC - person Ragnar; 29.05.2017
comment
как человек прошел здесь - person Omar; 11.01.2018
comment
@Omar, какую бы функцию вы ни назвали в Angular HTML, в данном случае sorterFunc, ng-repeat вызывает эту функцию с параметром, установленным на значение этого экземпляра повторения. Так как он говорит: ng-repeat = ЧЕЛОВЕК в людях | orderBy : sorterFunc, когда sorterFunc вызывается, значение person на этой итерации ng-repeat отправляется в качестве его параметра. - person Eureka; 10.09.2018
comment
Или, другими словами, | (труба) символ говорит: возьмите вывод выражения слева и пропустите его через вещь справа. Результатом функции left на каждой итерации является одно значение person. - person Eureka; 10.09.2018

Внутри вашей директивы ng-repeat вы используете числовой фильтр

<td>{{person.id | number}}</td>

Фильтры используются для форматирования вывода, но они не обновляют свойства модели. Например: person.id = 1234,56789 будет отображаться как 1 234,568.

Как упоминалось выше, вы должны преобразовать возраст в тип числа. Тогда orderBy будет работать как надо. Например, внутри вашего сервиса:

angular.forEach(People.details, function (detail) {
  detail.age = parseFloat(detail.age);
});
person SergeL    schedule 26.05.2013
comment
@SergL Я только что понял, что в примере с угловыми документами числа в данных JSON не заключены в кавычки. Я предполагаю, что это то, что я должен делать с моими данными JSON. - person dewd; 27.05.2013

если ваше значение orderBy является не переменной, указывающей на другую строку, а скорее атрибутом, по которому вы будете сортировать, вы должны поместить его в кавычки.

person in people | orderBy:'-id'

Если после того, как вы проанализировали свой int или float и все еще не сортируете правильно, это может быть из-за этого. ‹:/ (это моя дурацкая кепка)

person Ktel    schedule 27.05.2014

Я столкнулся с той же проблемой, когда работал с текстовым полем и ngModel, чтобы изменить значение модели, по которой я заказывал. Поскольку значение рассматривалось как строка.

С новым HTML5 <input type="number" /> Angular анализирует значение поля ввода к числу (я думаю, с плавающей запятой), которое помогло мне получить правильный порядок.

person naitsirch    schedule 23.04.2014

Пусть orderBy указывает на метод, принадлежащий области или его неизолированным предкам, и пусть этот метод возвращает число, полученное из строки. Возможно, вам придется написать директиву, наследующую область person, созданную экземплярами ngRepeat..., чтобы добавить этот метод.

Более того, в вашем случае возраст представляет собой строку, в которой он мог бы быть целым числом, поэтому числовая сортировка будет применяться изначально.

Если вы не можете изменить сервер данных, измените его на стороне клиента во время выборки.

person lib3d    schedule 26.05.2013

Лучше всего обновлять повторяющуюся коллекцию всякий раз, когда вызывается функция сортировки. Здесь я использую Lodash - orderBy просто для упорядочения коллекции на основе функции сортировщика. Допустим, сортировка вызывается при нажатии на заголовок столбца таблицы.

Пример:

Объект коллекции:

ctrl.people = [{"id":"42","firstname":"Sarah","lastname":"Dilby","age":"40","cars":"Yaris","salary": 700}, {"firstname":"Jason","lastname":"Diry","age":"5","id":"5","cars":"Lexia","salary": 500},{"id":"6","firstname":"Bilson","lastname":"Berby","age":"1","cars":"Tipo","salary": 400}];

Пользователь щелкает заголовок столбца для сортировки по возрасту:

<th class="col-age" data-ng-click="ctrl.sortColumn('age')">Age</th>

Метод называется:

ctrl.sortColumn('age'); // where age is column containing numbers only

Реализация метода:

ctrl.sortedCol = 'firstname';    //Default sort column

ctrl.sortColumn = (column) => {
    ctrl.sortedCol = column; //age
    let order = 'asc'; //you can decide the order based on your own logic
    ctrl.people = _.orderBy(ctrl.people, [ctrl.sorter], [order]);   //update the collection
};

ctrl.sortColumn(ctrl.sortedCol); //called on initial rendering

Функция сортировщика: возвращает отсортированную коллекцию на основе типа столбца.

ctrl.sorter = (item) => {
    const columnType = ctrl.getColumnType();
    if(item[ctrl.sortedCol] && columnType === 'string'){
        return item[ctrl.sortedCol].toLowerCase();
    } else if(item[ctrl.sortedCol] && columnType === 'number'){
        return parseInt(item[ctrl.sortedCol]);
    } else{
        return item[ctrl.sortedCol];
    }    
};

Определите тип столбца: может быть строка, число или даже дата.

ctrl.getColumnType = () => {
    if(ctrl.sortedCol === 'firstname' || ctrl.sortedCol === 'lastname' || ctrl.sortedCol === 'cars'){
        return 'string';
    } else if(ctrl.sortedCol === 'salary' || ctrl.sortedCol === 'age'){
        return 'number';
    }
};
person rach8garg    schedule 30.11.2017