Как перебрать элементы, возвращаемые функцией с помощью 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 ходов вы получаете ошибку.
Как вы можете это исправить
- Не создавайте новые объекты на каждом
getEntities()
вызов. - Если вам нужно создать новые объекты, вы можете добавить
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 и выше, в то время как первое решение не решает проблему. Так что, боюсь, пока это менее острое решение без недостатков в функциональности.