Angular orderBy number sorting as text in ng-repeat

会有一股神秘感。 提交于 2019-11-27 01:48:38

I think the most appropriate solution is to format the numbers I have on my JSON objects correctly, ie not to wrap them in quotes. So:

 [{"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"}]

becomes:

[{"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"}]

I'm guessing SergL's solution is good if it's not possible to correct the format of the JSON data.

To add to this, the issue in my specific case is to do with PHP's json_encode function on the server side. By default, it treats numbers as strings. To fix I had to add the JSON_NUMERIC_CHECK option to the encode method in the PHP script:

json_encode($assoc_array,JSON_NUMERIC_CHECK);

You don't have to modify your JSON. You can pass a function to orderBy filter like this:

$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>

Inside your ng-repeat directive you are using a number filter

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

Filters are used to format the output, but they don't update the Model properties. For example: person.id = 1234.56789 will be rendered as 1,234.568.

As mentioned above you have to convert age to type Number. Then orderBy will work as it should. For example inside your service:

angular.forEach(People.details, function (detail) {
  detail.age = parseFloat(detail.age);
});

if your orderBy value is not a variable pointing to another string but rather the attribute by which you'll be sorting, you must put it in quotes.

person in people | orderBy:'-id'

If, after you've parsed your int or float and are still not sorting correctly, it might be because of this. <:/ (that's my dunce cap)

I faced the same problem when I was working with a text field and ngModel to change the value of the model I was ordering by. Because the value was regarded as string.

With new HTML5 <input type="number" />, Angular parses the value of the input field to a number (float I think), which helped me to get the correct order.

Let orderBy point to a method owned by the scope or its not isolated ancestors and let this method return a number casted from the string. You may have to write a directive inheriting the person scope created by the ngRepeat instances.. to add this method.

Moreover in your case, the age is a string where it could have been an integer and so the numeric sort would be natively applied.

If you cannot change the data serverside then alter it clientside while fetching.

It is best to update your repeating collection whenever a sort function is called. Here I am using Lodash - orderBy just to order the collection based on a sorter function. Lets say the sort is called on click of table column head.

Example:

Collection object:

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}];

User clicks column head to sort by age:

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

Method called:

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

Method implementation:

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

Sorter function: Returns the sorted collection based on column type

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];
    }    
};

Decide column type: Can be string, number or even date

ctrl.getColumnType = () => {
    if(ctrl.sortedCol === 'firstname' || ctrl.sortedCol === 'lastname' || ctrl.sortedCol === 'cars'){
        return 'string';
    } else if(ctrl.sortedCol === 'salary' || ctrl.sortedCol === 'age'){
        return 'number';
    }
};
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!