Как отсортировать карту объектов 1: 1 в Angular JS ng-repeat

#javascript #angularjs #angularjs-ng-repeat #angularjs-orderby

#javascript #angularjs #angularjs-ng-repeat #angularjs-orderby

Вопрос:

Есть ли способ отсортировать карту объектов 1: 1 в angular.js использование фильтров (или любого другого метода) в блоке ng-repeat?

У меня есть:

 obj:{
     a:3,
     c:5,
     d:1,
     g:15
}
 

По сути, я хотел бы иметь возможность делать что-то вроде этого:

 <div ng-repeat="item in obj | orderBy:'value'"> {{ item.value }}</div>
 

Я хотел бы иметь возможность сортировать это представление данных либо по ключу, либо по значению. Я знаю, что angular OrderBy будет сортировать только массивы, поэтому он не будет сортировать этот объект. Однако, если бы я мог превратить этот объект в массив объектов с ключом и значением в качестве свойств (предпочтительно с использованием фильтра с именем ‘toArray’):

 var arr = [
  { 
     key:'a',
     value:'3'
  },
  {
    key:'c',
    value:5
  },
  ....
]
 

тогда я мог бы использовать что-то вроде этого:

 <div ng-repeat="item in obj | toArray | orderBy:'value'"> {{ item.value }}</div>
 

Однако любая попытка написать такой фильтр привела к достижению 10 итераций digest(). Ошибка прерывания!, поскольку она обновляет новый массив объектов на каждой итерации.

Каково наилучшее (или любое) решение для сортировки карты объектов 1: 1 без необходимости реструктуризации данных в контроллере?

Комментарии:

1. Пожалуйста, предоставьте код для вашего toArray фильтра, чтобы мы могли перейти оттуда. Удар в темноте: правильно ли toArray циклируется ваш дескриптор? Некоторые объекты AngularJS имеют циклы.

Ответ №1:

Попробуйте angular-underscore, который вводит функции подчеркивания в angular.js . Затем вы можете написать код, подобный:

 <div ng-repeat="item in values(obj) | orderBy:identity"> {{ item }}</div>
 

чтобы получить только значения; или

 <div ng-repeat="item in pairs(obj) | orderBy:last"> Key: {{ item[0] }}; Value: {{item[1]}}</div>
 

чтобы получить как ключи, так и значения.

Это действительно просто. Плунжер здесь: http://plnkr.co/edit/Zb4XpaQUXZ8nZJqR493b?p=preview

Комментарии:

1. это выглядит многообещающе, я вижу, что он упорядочивает список по значению от наименьшего к наибольшему значению. как бы вы изменили этот порядок ?… от наивысшего значения к наименьшему значению

2. @user1394625 просто добавьте :reverse параметр следующим образом: <div ng-repeat="item in values(obj) | orderBy:identity:true"> {{ item }}</div> . Вы можете обратиться к AngularJS doc OrderBy для получения дополнительной информации.

Ответ №2:

Вы думали о том, чтобы просто создать массив изначально в вашем контроллере вот так?

 $scope.items = [];
for(var key in obj) {
    if(obj.hasOwnProperty(key)) {
        $scope.items.push({ key: key, value: obj[key] });
    }
}
 

Затем повторить итерацию items ?

 <div ng-repeat="item in items|orderBy:'value'">{{ item.value }}</div>
 

По крайней мере, тогда вы заполняете массив только один раз. Это может быть проблемой, если исходный объект поступает из запроса или чего-то еще, но я думаю, вы могли бы довольно легко заполнить обратный вызов указанного запроса.

Комментарии:

1. На данный момент это единственное решение, которое я have…to сделайте это в контроллере. Я надеялся, что есть способ сделать это в представлении. Таким образом структурирован не только один объект, поэтому мне пришлось бы запускать каждый объект через функцию в контроллере. Не прерыватель сделки, но он выглядит чище, просто проходя через фильтр в представлении.

2. вероятно, вы могли бы каким-то образом использовать это как фильтр или директиву, но это не очень хорошо для производительности. Я полагаю, что он будет продолжать оценивать его каждый раз при запуске наблюдателя, поэтому вы будете генерировать этот массив каждый раз . Может быть, просто создайте сервис, который вы вводите в свой контроллер, чтобы сделать это? (например, Utils.somehelper)