Подтвердить что ты не робот

Директива ng-repeat сортирует данные при использовании (ключ, значение)

У меня есть код вроде этого с ng-repeat = "(ключ, значение) в данных". В контроллере:

  $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

Как избавиться от этой сортировки (странно), поскольку я хочу, чтобы ключи использовались в коде. Я проверил группу google, но была скрипка для использования двух массивов, в которых хранилось значение ключа. http://jsfiddle.net/Saulzar/puhML/3/b. Не хочешь идти с таким подходом.

4b9b3361

Ответ 1

Это ограничение JavaScript не Angular.

Из Третий выпуск ECMAScript:

4.3.3 Объект является членом типа Object. Это неупорядоченная коллекция свойств, каждая из которых содержит примитив значение, объект или функцию. Функция, хранящаяся в свойстве объект называется методом.

Из Спецификация языка 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
};

Ответ 2

EDIT: Я подал ошибку, не стесняюсь +1

ECMAScript не указывает порядок, в котором ключи должны быть итерированы, однако все основные браузеры реализуют объекты как связанные хэш-карту (сохраняет порядок), и многие библиотеки js зависят от этого поведения, и поэтому мы привыкли к этому, и это вряд ли изменится.

Angular с другой стороны (это полностью неожиданно) сортирует его по алфавиту. Я сам проверял исходный код, он жестко закодирован, и было бы неплохо, если бы он был разрешен в один прекрасный день. В противном случае функция (k, v) in obj полностью бесполезна.

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

Если это нормально, вы можете определить getter для длины:

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

В противном случае вам понадобится какой-то фильтр, который будет перебирать объект с помощью for(var k in obj) и сохранять результат в массиве.

Ответ 3

На самом деле есть ответ: он называется orderBy, а не sort:

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>

Ответ 4

Это исправлено с Angular 1.4.

Подробнее здесь:

Раньше порядок элементов при использовании ngRepeat для итерации по свойствам объекта гарантированно согласовывался путем сортировки ключей в алфавитном порядке.

Теперь порядок элементов зависит от браузера в зависимости от порядка, возвращаемого из итерации по объекту с помощью синтаксиса for key in obj.

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

Ответ 5

Мне удалось сортировать Object of Strings по ключу в алфавитном порядке, как это, с помощью 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>

Ответ 6

Object.keys не резервирует заказ - FYI 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/

Ответ 7

Ну, как объяснено в документации Angular для ngRepeat

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

при использовании его для итерации по свойствам объекта он не будет работать

Встроенные фильтры orderBy и фильтр не работают с объектами, и выдает ошибку, если используется с одним.

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