Angular orderBy 数字排序为 ng-repeat 中的文本
Posted
技术标签:
【中文标题】Angular orderBy 数字排序为 ng-repeat 中的文本【英文标题】:Angular orderBy number sorting as text in ng-repeat 【发布时间】:2013-05-21 18:41:51 【问题描述】:我有这些数据:
["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>
非常感谢您能帮助我理解为什么数字数据不按数字排序,以及为什么按文本排序。
【问题讨论】:
【参考方案1】:我认为最合适的解决方案是正确格式化 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 函数有关。默认情况下,它将数字视为字符串。为了解决这个问题,我必须在 PHP 脚本中的 encode 方法中添加 JSON_NUMERIC_CHECK
选项:
json_encode($assoc_array,JSON_NUMERIC_CHECK);
【讨论】:
我今天也只需要做 JSON_NUMERIC_CHECK 的事情。不错。 我第一次使用JSON_NUMERIC_CHECK
,真是太棒了。
JSON_NUMERIC_CHECK 太棒了。这就像一个魅力,谢谢@dewd!
仅供参考 JSON_NUMERIC_CHECK,也可以破坏东西。它删除前导零。例如。电话号码,0401231234 变为 401231234。
@Firze 我从不认为电话号码是一个“数字”,它应该始终是一个字符串。【参考方案2】:
您不必修改 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>
【讨论】:
如何降序排列? 要按降序排列,您可以在 parseInt() 之前添加 -: return - (parseInt(person.id));甚至更好的是,你可以在 sorterFunc 中添加一个参数,指定排序类型 ASC 或 DESC 人是怎么过来的 @Omar,无论您在 Angular HTML 中命名什么函数,在本例中为“sorterFunc”,ng-repeat 都会调用该函数,并将其参数设置为该重复实例的值。因此,既然它说:ng-repeat="PERSON in people | orderBy : sorterFunc",当 sorterFunc 被称为“person”的值时,在 ng-repeat 的迭代中,作为其参数发送。 或者换句话说,“|” (管道)字符表示将左侧表达式的输出,并将其传递给右侧的事物。左侧的输出,在每次迭代中,都是 person 的单个值。【参考方案3】:在您的 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);
);
【讨论】:
@SergL 我刚刚在 Angular 文档示例中指出,JSON 数据中的数字不被引号包裹。我猜这就是我应该对我的 JSON 数据做的事情。【参考方案4】:如果您的 orderBy 值不是指向另一个字符串的变量,而是您将用于排序的属性,则必须将其放在引号中。
person in people | orderBy:'-id'
如果在您解析完 int 或 float 后仍无法正确排序,则可能是因为这个原因。 <:>
【讨论】:
【参考方案5】:当我使用文本字段和 ngModel 来更改我订购的模型的值时,我遇到了同样的问题。因为该值被视为字符串。
使用新的 HTML5 <input type="number" />
,Angular 将输入字段的值解析为一个数字(我认为是浮点数),这有助于我获得正确的顺序。
【讨论】:
【参考方案6】:让orderBy
指向由作用域或其非独立祖先拥有的方法,并让该方法返回从字符串转换的数字。
您可能必须编写一个指令来继承由 ngRepeat 实例创建的 person
范围。添加此方法。
此外,在您的情况下,年龄是一个字符串,它可能是一个整数,因此将本机应用数字排序。
如果您无法更改数据服务器端,则在获取时更改它的客户端。
【讨论】:
【参考方案7】:最好在调用排序函数时更新您的重复集合。在这里,我使用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';
;
【讨论】:
以上是关于Angular orderBy 数字排序为 ng-repeat 中的文本的主要内容,如果未能解决你的问题,请参考以下文章
AngularJS在模板中使用orderBy ng-repeat值的全局变量