48

我有一个类似这样的代码,其中 ng-repeat = "(key,value) in data"。在控制器中:

  $scope.Dates = {"Today":"30",
                  "This Week":"42",
                  "This Month": "Oct",
                  "This Quarter" : "Bad",
                  "This Year" : 2013
                                }

和 ng-repeat 指令为

<div ng-repeat="(key,value) in Dates">
{{key}} ==> {{value}}
</div>

输出按排序顺序排列为

This Month ==> Oct
This Quarter ==> Bad
This Week ==> 42 
This Year ==> 2013
Today ==> 30

如何摆脱这种排序(奇怪),因为我希望在代码中使用键。我检查了谷歌组,但有一个使用两个数组的小提琴,其中一个数组存储键值。http://jsfiddle.net/Saulzar/puhML/3/b。不想采用这种方法。

4

7 回答 7

65

这是 JavaScript 而不是 Angular 的限制。

来自ECMAScript 第三版

4.3.3 对象是对象类型的成员。它是一个无序的属性集合,每个属性都包含一个原始值、对象或函数。存储在对象属性中的函数称为方法。

来自ECMAScript 语言规范

未指定枚举属性 [...] 的 [...] 顺序 。

Angular显式地对对象键进行排序,以便至少提供某种持久性行为。

解决方法是迭代提取的键:

<div ng-repeat="key in keys(Dates)">
  {{key}} ==> {{Dates[key]}}
</div>
$scope.keys = function(obj){
  return obj? Object.keys(obj) : [];
}

$scope.Dates = {
  "Today":"30",
  "This Week":"42",
  "This Month": "Oct",
  "This Quarter" : "Bad",
  "This Year" : 2013
};
于 2013-10-30T08:23:45.133 回答
10

编辑:我已经提交了一个错误请随时 +1

ECMAScript 没有指定迭代键的顺序,但是所有主流浏览器都将对象实现为链接的哈希映射(保留顺序),并且很多 js 库都依赖于这种行为,所以我们已经习惯了,而且几乎不会改变。

另一方面,Angular(这是完全出乎意料的)按字母顺序对其进行排序。我自己检查了源代码,那里是硬编码的,如果有一天能解决就好了。否则该(k, v) in obj功能完全没用

你真的不能做任何事情,欺骗角度认为你的结果是一个数组对任何事情都没有用,因为你需要数字键......

如果这没问题,您可以定义 getter 的长度:

Object.defineProperty(yourResultObjectOrPrototype, 'length', {
  get: function(){
    return Object.keys(this).length;
  }
})

否则,您将需要某种过滤器来迭代对象for(var k in obj)并将结果存储在数组中。

于 2014-02-11T10:33:25.003 回答
7

实际上有一个答案:它被称为 orderBy 而不是排序:

https://docs.angularjs.org/api/ng/filter/orderBy

{{ orderBy_expression | orderBy : expression : reverse}}

<tr ng-repeat="friend in friends | orderBy:'-age'">
      <td>{{friend.name}}</td>
      <td>{{friend.phone}}</td>
      <td>{{friend.age}}</td>
    </tr>

您的列表只需要是一个列表,您可能需要一个索引来了解设置顺序

$scope.Dates = [{index:1, "Today":"30"},
                  {index:2,"This Week":"42"},
                  {index:3,"This Month": "Oct"},
                  {index:4,"This Quarter" : "Bad"},
                  {index:5,"This Year" : 2013}]

接着

<tr ng-repeat="(key, value) in Dates | orderBy:'index'">
          <td>{{key}}</td>
          <td>{{value}}</td>
         </tr>
于 2015-04-23T23:59:40.987 回答
6

这是从 Angular 1.4 开始修复的

在此处查看详细信息:

以前,当使用 ngRepeat 迭代对象属性时,通过将键排序为字母顺序来保证项目的顺序是一致的。

for key in obj现在,项目的顺序取决于浏览器,基于使用语法迭代对象返回的顺序。

似乎浏览器通常遵循按定义顺序提供密钥的策略......

于 2015-07-07T19:55:13.453 回答
2

我可以使用 ng-repeat 像这样按字母顺序对字符串对象进行排序!

在我的控制器中:

$scope.build_config = {
  build_path :  "/x/eng/build",
  arch : "x86",
  variant : "debug",
  run_method : "boot", 
};

$scope.get_keys = function (obj) {
  if (obj)
    return Object.keys(obj);
};

在我的 HTML 中:

<tr ng-repeat="key in get_keys(build_config) | orderBy:'toString()'">
      <td> {{key}} </td>
      <td> {{selected.build_config[key]}} </td>
</tr>
于 2016-04-07T20:55:45.010 回答
1

Object.keys 不保留订单 - 仅供参考 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

// 具有随机键顺序的数组对象

var an_obj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(an_obj)); // console: ['2', '7', '100']

我将其转换为对象数组

$scope.Dates = [
        { id: "Today",      value:"30" },
        { id: "This Week",  value:"42" },
        { id: "This Month", value: "Oct" },
        { id: "This Quarter", value : "Bad" },
        { id: "This Year",  value : 2013 }
    ];

<li ng-repeat="date in Dates">{{date.id}} -> {{date.value}}</li>

http://jsfiddle.net/2hqew68k/1/

于 2016-04-19T18:10:34.473 回答
0

好吧,正如 Angular 的 ngRepeat 文档中所解释的那样

https://docs.angularjs.org/api/ng/directive/ngRepeat#iterating-over-object-properties

当使用它来迭代对象的属性时,它将不起作用

内置过滤器 orderBy 和 filter 不适用于对象,如果与对象一起使用会抛出错误。

在这种情况下,我认为最好的解决方案是使用数组而不是对象及其属性。因此,只需将其转换为数组,例如迭代对象的属性并推送到新数组。毕竟,我认为这将是集合的自然选择,而不是具有许多属性的单个对象。

于 2017-05-19T07:09:47.243 回答