Как перебрать элементы, возвращаемые функцией с помощью ng-repeat?

Я хочу создавать div повторно, элементы - это объекты, возвращаемые функцией. Однако следующий код сообщает об ошибках: 10 $digest() достигнуто. Aborting! jsfiddle здесь: http://jsfiddle.net/BraveOstrich/awnqm/

<body ng-app>
  <div ng-repeat="entity in getEntities()">
    Hello {{entity.id}}!
  </div>
</body>

4 ответа

Решение

Краткий ответ: вам действительно нужна такая функция или вы можете использовать свойство? http://jsfiddle.net/awnqm/1/

Длинный ответ

Для простоты опишу только ваш случай - ngRepeat для массива объектов. Также я опущу некоторые детали.

AngularJS использует грязную проверку для обнаружения изменений. Когда приложение запускается, оно запускается $digest за $rootScope, $digest выполнит обход в глубину для иерархии области. У всех областей есть список часов. Каждые часы имеют последнее значение (изначально initWatchVal). Для каждой области для всех часов $digest запускает его, получает текущее значение (watch.get(scope)) и сравнивает это с watch.last, Если текущее значение не равно watch.last (всегда для первого сравнения) $digest наборы dirty в true, Когда все области обработаны, если dirty == true$digest начинает еще один глубинный обход $rootScope, $digest заканчивается, когда dirty == false или число обходов == 10. В последнем случае ошибка "10 $digest() достигли итераций". будет зарегистрирован.

Теперь о ngRepeat, Для каждого watch.get вызовите это сохраняет объекты из коллекции (возвращая значение getEntities) с дополнительной информацией в кеше (HashQueueMap от hashKey). Для каждого watch.get вызов ngRepeat пытается получить объект его hashKey из кеша Если он не существует в кеше, ngRepeat сохраняет его в кеше, создает новую область видимости, помещает объект в него, создает элемент DOM и т. д.

Теперь о hashKey, Обычно hashKey уникальный номер, сгенерированный nextUid(), Но это может быть функция. hashKey сохраняется в объекте после генерации для будущего использования.

Почему ваш пример генерирует ошибку: функция getEntities() всегда возвращает массив с новым объектом. Этот объект не имеет hashKey и не существует в ngRepeat кэш. Так ngRepeat на каждой watch.get создает новые возможности для него с новыми часами для {{entity.id}}, Это посмотреть на первую watch.get имеет watch.last == initWatchVal, Так watch.get() != watch.last, Так $digest начинается новый ход. Так ngRepeat создает новые возможности с новыми часами. Итак... после 10 ходов вы получаете ошибку.

Как вы можете это исправить

  1. Не создавайте новые объекты на каждом getEntities() вызов.
  2. Если вам нужно создать новые объекты, вы можете добавить hashKey метод для них. Смотрите эту тему для примеров.

Надеюсь, что люди, которые знакомы с внутренностями AngularJS, исправят меня, если я ошибаюсь.

Инициализируйте массив вне повторения

<body ng-app>
   <div ng-init="entities = getEntities()">
       <div ng-repeat="entity in entities">
           Hello {{entity.id}}!
       </div>
   </div>
</body>

Об этом сообщили здесь и получили этот ответ:

Ваш геттер не идемпотентен и меняет модель (генерируя новый массив каждый раз, когда он вызывается). Это заставляет angular продолжать называть это в надежде на то, что модель в конечном итоге стабилизируется, но это никогда не делает так, что angular сдается и выдает исключение.

Значения, возвращаемые геттером, равны, но не идентичны, и в этом проблема.

Это поведение исчезнет, ​​если вы переместите массив за пределы основного контроллера:

var array = [{id:'angularjs'}];
function Main($scope) {
    $scope.getEntities = function(){return array;};
};

потому что теперь он возвращает один и тот же объект каждый раз. Возможно, вам придется изменить архитектуру вашей модели, чтобы использовать свойство в области вместо функции:

Мы обошли его, присвоив результат метода контроллера свойству и выполнив команду ng: repeat против него.

Основано на комментарии @przno

<body ng-app>
  <div ng-repeat="item in t = angular.equals(t, getEntities()) ? t : getEntities()">
    Hello {{item.id}}!
  </div>
</body>

Кстати, второе решение @ Артем Андреев предполагает, что не работает в Angular 1.1.4 и выше, в то время как первое решение не решает проблему. Так что, боюсь, пока это менее острое решение без недостатков в функциональности.

Другие вопросы по тегам