33

我有这个数据:

[{"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 中按 id 或按年龄排序时,它会将数字排序为文本。由于我在任何地方都找不到书面说明这是一个问题,我猜我的代码有问题。我已经创建了这个小提琴: http: //jsfiddle.net/vsbGH/1/对不起模板,但 jsfiddle 不允许在 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>

非常感谢您能帮助我理解为什么数字数据没有按数字排序,以及为什么它按文本排序。

4

7 回答 7

51

我认为最合适的解决方案是正确格式化我的 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"}]

如果无法更正 JSON 数据的格式,我猜 SergL 的解决方案会很好。

除此之外,在我的具体情况下,问题与服务器端 PHP 的 json_encode 函数有关。默认情况下,它将数字视为字符串。为了解决这个问题,我必须JSON_NUMERIC_CHECK在 PHP 脚本中的 encode 方法中添加选项:

json_encode($assoc_array,JSON_NUMERIC_CHECK);
于 2013-05-27T10:06:29.200 回答
31

您不必修改 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>
于 2016-04-29T17:49:51.370 回答
15

在您的 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);
});
于 2013-05-26T23:49:15.793 回答
5

如果您的 orderBy 值不是指向另一个字符串的变量,而是您将用于排序的属性,则必须将其放在引号中。

person in people | orderBy:'-id'

如果在解析完 int 或 float 之后仍然无法正确排序,可能是因为这个。<:/ (那是我的傻帽)

于 2014-05-27T22:13:12.823 回答
3

当我使用文本字段和 ngModel 来更改我订购的模型的值时,我遇到了同样的问题。因为该值被视为字符串。

使用新的 HTML5 <input type="number" />,Angular 将输入字段的值解析为一个数字(我认为是浮点数),这有助于我获得正确的顺序。

于 2014-04-23T19:21:57.827 回答
0

orderBy指向由作用域或其非孤立祖先拥有的方法,并让该方法返回从字符串转换的数字。您可能必须编写一个指令来继承person由 ngRepeat 实例创建的范围。添加此方法。

此外,在您的情况下,年龄是一个字符串,它可能是一个整数,因此将本机应用数字排序。

如果您无法更改数据服务器端,则在获取时更改它的客户端。

于 2013-05-26T22:29:52.613 回答
-1

最好在调用排序函数时更新您的重复集合。在这里,我使用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

Sorter 函数:根据列类型返回排序后的集合

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';
    }
};
于 2017-11-30T15:14:08.350 回答