Ошибка: достигнуто 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 с рабочим примером.

bmleite
источник
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);
});
squillman
источник
Это звучит так же, как проблема, которую я имею. Простая функция, которая ничего не обновляла, но создавала локальный массив, повторяла один существующий массив $ 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 с областью действия. И назначьте его только один раз.

JDev
источник
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 = "" . Работал на меня.

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

Alex
источник
0

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

Zsolti
источник
0

у меня была похожая ошибка, потому что я определил

нг-класс = "GetLink ()"

вместо того

нг-клик = "GetLink ()"

Сатиш Кумар Сонкер
источник
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);
aCMoFoCord
источник
0

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

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

майкл хансен079
источник