Ошибка: достигнуто 10 $ digest (). Aborting! с динамическим предикатом sortby


134

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

<div ng-controller="AngularCtrl" ng-app>
  <div ng-repeat="user in users | orderBy:predicate:reverse | limitTo:10">
    <div ng-init="user.score=user.id+1">
        {{user.name}} and {{user.score}}
    </div>
  </div>
</div>

И соответствующий угловой контроллер.

function AngularCtrl($scope) {
    $scope.predicate = 'score';
    $scope.reverse = true;
    $scope.users = [{id: 1, name: 'John'}, {id: 2, name: 'Ken'}, {id: 3, name: 'smith'}, {id: 4, name: 'kevin'}, {id: 5, name: 'bob'}, {id: 6, name: 'Dev'}, {id: 7, name: 'Joe'}, {id: 8, name: 'kevin'}, {id: 9, name: 'John'}, {id: 10, name: 'Ken'}, {id: 11, name: 'John'}, {id: 1, name: 'John'}, {id: 2, name: 'Ken'}, {id: 3, name: 'smith'}, {id: 4, name: 'kevin'}, {id: 5, name: 'bob'}, {id: 6, name: 'Dev'}, {id: 7, name: 'Joe'}, {id: 8, name: 'kevin'}, {id: 9, name: 'John'}, {id: 10, name: 'Ken'}]
}

Когда я запускаю приведенный выше код, я получаю сообщение об ошибке Error: 10 $ digest (). Aborting! ошибка в моей консоли.

Я создал jsfiddle для того же.

Предикат сортировки инициализируется только внутри ng-repeat, а также применяется ограничение на количество объектов. поэтому я считаю, что наличие наблюдателей sortby и limitTo является причиной ошибки.

Если $ scope.reverse имеет значение false (в порядке возрастания оценки), то это не ошибка.

Может кто-нибудь помочь мне понять, что здесь не так? Очень ценю вашу помощь.


Если вы удалите оператор if, это все еще ошибка?
Мэтью Берг

Спасибо за ваш ответ Мэтью! Я поставил проблему неправильно. Проблема, похоже, связана с фильтрами sortby и limitTo. Я обновил вопрос с JSFiddle. Очень ценю вашу помощь.
Пухлый мальчик

это угловатая вещь. Вам нужно запомнить свои функции и затем запомнить состояние. Поймай мой ответ на stackoverflow.com/questions/14376879/…
Хулио Маринс

Ответы:


116

Пожалуйста, проверьте это jsFiddle . (Код в основном тот же, что вы опубликовали, но я использую элемент вместо окна для привязки событий прокрутки).

Насколько я вижу, нет проблем с кодом, который вы разместили. Ошибка, о которой вы упоминали, обычно возникает, когда вы создаете цикл изменений свойства. Например, например, когда вы отслеживаете изменения определенного свойства, а затем изменяете значение этого свойства на слушателе:

$scope.$watch('users', function(value) {
  $scope.users = [];
});

Это приведет к сообщению об ошибке:

Uncaught Ошибка: 10 $ digest () достигнуто. Aborting!
Наблюдатели уволены за последние 5 итераций: ...

Убедитесь, что в вашем коде нет подобных ситуаций.

Обновить:

Это ваша проблема:

<div ng-init="user.score=user.id+1"> 

Вы не должны изменять объекты / модели во время рендеринга или иным образом, это вызовет новый рендеринг (и, следовательно, цикл , который вызывает «Ошибка: 10 $ digest () достигнут итераций. Прерывание!» ).

Если вы хотите обновить модель, делайте это на контроллере или в директиве, а не в представлении. angularjs документация рекомендует не использоватьng-init точно , чтобы избежать таких ситуаций:

Используйте директиву ngInit в шаблонах (только для игрушек / примеров приложений, не рекомендуется для реальных приложений)

Вот jsFiddle с рабочим примером.


1
К вашему сведению, вместо angular.element(w).bind()вас можно использовать element.bind().
Марк Райкок

Большое спасибо Бмлеите и Марку. Я поставил проблему неправильно. Пожалуйста, смотрите мои комментарии выше. Я обновил вопрос с JSFiddle. Очень ценю вашу помощь.
пухлый мальчик

Большое спасибо @bmleite! Просто пытаюсь понять больше. Но почему, если $ scope.reverse = false (возрастающий счет) не приводит к ошибке?
Пухлый мальчик

Для повышения и понижения следует использовать префиксы «+» и «-» соответственно (т. Е. «+ Оценка» и «-score»). Подробнее об этом здесь .
bmleite

1
Этот ответ решил мою проблему. Это хорошее объяснение состоит в том, что оно описывает проблему: ошибка итераций $ digest () возникает, когда вы пытаетесь изменить свойство в то же время, когда выполняете цикл. Таким образом, каждое изменение свойства запускает обновление представления (UI), и значение angular в конечном итоге достигает 10 циклов. Пример jsFiddle помещает изменение свойства в контроллер. Изменение свойства в представлении приводит к этой ошибке.
Мбокил

9

Причиной этой ошибки для меня было ...

ng-if="{{myTrustSrc(chat.src)}}"

в моем шаблоне

Это заставляет функцию myTrustSrc в моем контроллере вызываться в бесконечном цикле. Если я уберу ng-if из этой строки, то проблема решена.

<iframe ng-if="chat.src" id='chat' name='chat' class='chat' ng-src="{{myTrustSrc(chat.src)}}"></iframe>

Функция вызывается только несколько раз, когда ng-if не используется. Мне все еще интересно, почему функция вызывается более одного раза с помощью ng-src?

Это функция в контроллере

$scope.myTrustSrc = function(src) {
    return $sce.trustAsResourceUrl(src);
}

Мне все еще интересно, почему функция вызывается более одного раза с помощью ng-src? - потому что angular пытается создать html несколько раз, пока не получит 2 идентичных результата. в этом смысл итерации ошибки $ 10 digest (), он пробовал 10 раз и никогда не получал 2 одинаковых результата
bresleveloper

@bresleveloper Не могли бы вы предоставить ссылку с этой информацией? Спасибо.
Вилла

@Willa посмотреть здесь docs.angularjs.org/api/ng/type/$rootScope.Scope CTRF + F это «Перекладка предел итерация 10 , чтобы предотвратить бесконечный затор петли»
bresleveloper

Спасибо. Это помогло.
Вилла

7

Для меня это было то, что я передавал результат функции как двухстороннее связывание ввода '=' в директиву, которая каждый раз создавала новый объект.

поэтому у меня было что-то подобное:

<my-dir>
   <div ng-repeat="entity in entities">
      <some-other-dir entity="myDirCtrl.convertToSomeOtherObject(entity)"></some-other-dir>
   </div>
</my-dir>

и метод контроллера на my-dir был

this.convertToSomeOtherObject(entity) {
   var obj = new Object();
   obj.id = entity.Id;
   obj.value = entity.Value;
   [..]
   return obj;
}

который, когда я сделал, чтобы

this.convertToSomeOtherObject(entity) {
   var converted = entity;
   converted.id = entity.Id;
   converted.value = entity.Value;
   [...]
   return converted;
}

решил проблему!

Надеюсь, это кому-нибудь поможет :)


5

У меня есть еще один пример чего-то, что вызвало это. Надеюсь, это поможет для дальнейшего использования. Я использую AngularJS 1.4.1.

У меня была эта разметка с несколькими вызовами пользовательской директивы:

<div ng-controller="SomeController">
    <myDirective data="myData.Where('IsOpen',true)"></myDirective>
    <myDirective data="myData.Where('IsOpen',false)"></myDirective>
</div>

myDataявляется массивом и Where()является методом расширения, который перебирает массив, возвращая новый массив, содержащий любые элементы из оригинала, где свойство IsOpen соответствует значению bool во втором параметре.

В контроллере я установил $scope.dataтак:

DataService.getData().then(function(results){
    $scope.data = results;
});

Вызов Where()метода расширения из директивы, как в приведенной выше разметке, был проблемой. Чтобы исправить эту проблему, я переместил вызов метода расширения в контроллер вместо разметки:

<div ng-controller="SomeController">
    <myDirective data="openData"></myDirective>
    <myDirective data="closedData"></myDirective>
</div>

и новый код контроллера:

DataService.getData().then(function(results){
    $scope.openData = results.Where('IsOpen',true);
    $scope.closedData = results.Where('IsOpen',false);
});

Это звучит так же, как проблема, которую я имею. Простая функция, которая ничего не обновляла, но создавала локальный массив, повторяла один существующий массив $ scope, создавала объекты в локальном массиве и возвращала. Однажды позвонив и сохранив его в члене $ scope, вы решите проблему. Спасибо. Жаль, что я не знаю, в чем проблема с использованием метода напрямую.
AgilePro

2

Довольно поздно на вечеринку, но моя проблема происходила из-за дефекта в ui-router в angular 1.5.8. Следует упомянуть, что эта ошибка появилась только при первом запуске приложения, и после этого она больше не повторялась. Этот пост от github решил мою проблему. В основном ошибка связана с $urlRouterProvider.otherwise("/home") решением было обходным путем, как это:

$urlRouterProvider.otherwise(function($injector, $location) {
   var $state = $injector.get("$state");
   $state.go("your-state-for-home");
});

2

Для начала проигнорируйте все ответы, указав использовать $ watch. Angular уже работает от слушателя. Я гарантирую вам, что вы все усложняете, просто думая в этом направлении.

Игнорируйте все ответы, которые сообщают пользователю $ timeout. Вы не можете знать, сколько времени займет загрузка страницы, поэтому это не лучшее решение.

Вам нужно только знать, когда страница завершит рендеринг.

<div ng-app='myApp'>
<div ng-controller="testctrl">
    <label>{{total}}</label>
    <table>
      <tr ng-repeat="item in items track by $index;" ng-init="end($index);">
        <td>{{item.number}}</td>
      </tr>
    </table>
</div>

var app = angular.module('myApp', ["testctrl"]);
var controllers = angular.module("testctrl", []);
 controllers.controller("testctrl", function($scope) {

  $scope.items = [{"number":"one"},{"number":"two"},{"number":"three"}];

  $scope.end = function(index){
  if(index == $scope.items.length -1
        && typeof $scope.endThis == 'undefined'){

            ///  DO STUFF HERE
      $scope.total = index + 1;
      $scop.endThis  = true;
 }
}
});

Отслеживайте ng-repeat по $ index и, когда длина массива равна индексу, останавливайте цикл и выполняйте свою логику.

jsfiddle


1

Я получил эту ошибку в контексте управления угловым деревом. В моем случае это были варианты дерева. Я возвращал treeOptions () из функции. Он всегда возвращал один и тот же объект. Но Angular волшебным образом думает, что это новый объект, а затем запускает цикл дайджеста. Вызывает рекурсию дайджестов. Решением было связать treeOptions с областью действия. И назначьте его только один раз.


1

Это странно ... У меня точно такая же ошибка, произошедшая с другой вещью. Когда я создавал свой контроллер, я передавал параметр $ location, например так:

App.controller('MessageController', function ($scope, $http, $log, $location, $attrs, MessageFactory, SocialMessageFactory) {
   // controller code
});

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

Поэтому я просто удалил $ location из параметра создания контроллера, и он снова заработал , без этой ошибки. Или, если вам абсолютно необходимо использовать $ location из angular, вы должны удалить все <a href="#">link</a>ссылки в вашей странице шаблона и написать href = "" . Работал на меня.

Надеюсь, что это может помочь однажды.



0

Это случилось со мной сразу после обновления Firefox до версии 51. После clearing the cacheэтого проблема исчезла.



0

Это произошло со мной после обновления с угловой версии 1.6 -> 1.7 при использовании $ sce.trustAsResourceUrl () в качестве возвращаемого значения функции, вызываемой из ng-src. Вы можете увидеть эту проблему, упомянутую здесь .

В моем случае мне пришлось изменить следующее.

<source ng-src="{{trustSrc(someUrl)}}" type='video/mp4' />
trustSrc = function(url){
    return $sce.trustAsResourceUrl(url);
};

в

<source ng-src='{{trustedUrl}} type='video/mp4' />
trustedUrl = $sce.trustAsResourceUrl(someUrl);

0

Я получил точно такую ​​же ошибку, используя AngularJS 1.3.9, когда я в своем пользовательском фильтре сортировки вызвал Array.reverse ()

После того, как я удалил это, это будет хорошо.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.