Błąd: osiągnięto 10 $ streszczenia () iteracji. Przerwanie! z dynamicznym predykatem sortby

134

Mam następujący kod, który powtarza się i wyświetla nazwę użytkownika i jego wynik:

<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>

I odpowiedni kontroler kątowy.

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'}]
}

Kiedy uruchamiam powyższy kod, otrzymuję błąd: osiągnięto iteracje 10 $ digest (). Przerwanie! błąd w mojej konsoli.

Stworzyłem jsfiddle dla tego samego.

Predykat sortowania jest inicjowany tylko w obrębie ng-repeat, a także nakładany jest limit na liczbę obiektów. więc uważam, że posiadanie jednocześnie obserwatorów sortby i limitTo jest przyczyną błędu.

Jeśli $ scope.reverse ma wartość false (rosnąca kolejność wyniku), to nie powoduje błędu.

Czy ktoś może mi pomóc zrozumieć, co tu jest nie tak? Bardzo doceniam twoją pomoc.

Pulchny chłopiec
źródło
Czy po usunięciu instrukcji if nadal występuje błąd?
Mathew Berg
Dzięki za odpowiedź Mathew! Błędnie zdiagnozowałem problem. Wydaje się, że problem dotyczy filtrów sortby i limitTo. Zaktualizowałem pytanie za pomocą JSFiddle. Bardzo doceniam twoją pomoc.
Chubby Boy
to jest kanciasta rzecz. Musisz zapamiętać swoje funkcje, a następnie zapamiętać stan. Zobacz moją odpowiedź na stackoverflow.com/questions/14376879/ ...
Julio Marins

Odpowiedzi:

116

Sprawdź to jsFiddle . (Kod jest w zasadzie taki sam, jak opublikowałeś, ale używam elementu zamiast okna do powiązania zdarzeń przewijania).

O ile widzę, nie ma problemu z opublikowanym przez Ciebie kodem. Wspomniany błąd zwykle występuje podczas tworzenia pętli zmian w właściwości. Na przykład, gdy obserwujesz zmiany w określonej właściwości, a następnie zmieniasz wartość tej właściwości w odbiorniku:

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

Spowoduje to wyświetlenie komunikatu o błędzie:

Nieprzechwycony błąd: osiągnięto iteracje 10 $ straw (). Przerwanie!
Obserwatorzy zwolnieni w ostatnich 5 iteracjach: ...

Upewnij się, że Twój kod nie zawiera tego rodzaju sytuacji.

aktualizacja:

To jest twój problem:

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

Nie powinieneś zmieniać obiektów / modeli podczas renderowania lub w inny sposób, wymusi to nowy render (i w konsekwencji pętlę , która spowoduje 'Błąd: osiągnięto iteracje 10 $ straw (). Przerywanie!' ).

Jeśli chcesz zaktualizować model, zrób to na kontrolerze lub na dyrektywie, nigdy w widoku. angularjs dokumentacja nie zaleca stosowanieng-init dokładnie, aby uniknąć tego rodzaju sytuacji:

Użyj dyrektywy ngInit w szablonach (tylko dla zabawek / przykładowych aplikacji, niezalecane dla rzeczywistych aplikacji)

Oto jsFiddle z działającym przykładem.

bmleite
źródło
1
FYI, zamiast angular.element(w).bind()ciebie możesz użyć element.bind().
Mark Rajcok,
Wielkie dzięki bmleite i Mark. Błędnie zdiagnozowałem problem. Zobacz moje komentarze powyżej. Zaktualizowałem pytanie za pomocą JSFiddle. Bardzo doceniam twoją pomoc.
Chubby Boy
Bardzo dziękuję @bmleite! Po prostu próbuję zrozumieć więcej. Ale dlaczego tak się dzieje, jeśli $ scope.reverse = false (rosnąca kolejność wyniku) nie powoduje błędu?
Chubby Boy
Rosnąco i malejąco należy używać odpowiednio przedrostków „+” i „-” (tj. „+ Score” i „-score”). Więcej informacji na ten temat tutaj .
bmleite
1
Ta odpowiedź rozwiązała mój problem. Wyjaśnienie jest dobre, ponieważ opisuje problem: błąd iteracji $ digest () pojawia się, gdy próbujesz zmodyfikować właściwość w tym samym czasie, gdy przechodzisz przez pętlę. Zatem każda zmiana właściwości wyzwala aktualizację widoku (UI), a kąt ostatecznie osiąga maksimum przy 10 pętlach. Przykład jsFiddle umieszcza zmianę właściwości w kontrolerze. Zmiana właściwości w Widoku powoduje ten błąd.
mbokil
9

Przyczyną tego błędu było dla mnie ...

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

w moim szablonie

Powoduje to wywołanie funkcji myTrustSrc w moim kontrolerze w nieskończonej pętli. Jeśli usunę ng-if z tej linii, problem zostanie rozwiązany.

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

Funkcja jest wywoływana tylko kilka razy, gdy nie jest używana funkcja ng-if. Nadal zastanawiam się, dlaczego funkcja jest wywoływana więcej niż raz z ng-src?

To jest funkcja kontrolera

$scope.myTrustSrc = function(src) {
    return $sce.trustAsResourceUrl(src);
}
Natus Drew
źródło
Nadal zastanawiam się, dlaczego funkcja jest wywoływana więcej niż raz z ng-src? - ponieważ angular próbuje utworzyć kod HTML kilka razy, aż uzyska 2 identyczne wyniki. to jest znaczenie błędu 10 $ Digest () iteracji, próbował 10 razy i nigdy nie uzyskał 2 identycznych wyników
bresleveloper
@bresleveloper czy możesz podać link z tymi informacjami? Dzięki.
Willa
@Willa spójrz tutaj docs.angularjs.org/api/ng/type/$rootScope.Scope CTRF + F this "Limit powtórzeń iteracji wynosi 10, aby zapobiec zakleszczeniu nieskończonej pętli"
bresleveloper
Dzięki. To pomogło.
Willa
7

Dla mnie było to tak, że przekazywałem wynik funkcji jako dwukierunkowe dane wejściowe „=” do dyrektywy, która za każdym razem tworzyła nowy obiekt.

więc miałem coś takiego:

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

a metoda kontrolera w my-dir to

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

co kiedy zrobiłem

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

Rozwiązać problem!

Mam nadzieję, że to komuś pomoże :)

Michail Michailidis
źródło
5

Mam inny przykład czegoś, co to spowodowało. Mam nadzieję, że pomoże to w przyszłości. Używam AngularJS 1.4.1.

Miałem ten znacznik z wieloma wywołaniami dyrektywy niestandardowej:

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

myDatajest tablicą i Where()jest metodą rozszerzającą, która iteruje po tablicy, zwracając nową tablicę zawierającą wszystkie elementy z oryginału, w przypadku gdy właściwość IsOpen jest zgodna z wartością bool w drugim parametrze.

W kontrolerze ustawiam $scope.datatak:

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

Where()Problem polegał na wywołaniu metody rozszerzenia z dyrektywy, jak w powyższym znaczniku. Aby rozwiązać ten problem, przeniosłem wywołanie do metody rozszerzenia do kontrolera zamiast znaczników:

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

i nowy kod kontrolera:

DataService.getData().then(function(results){
    $scope.openData = results.Where('IsOpen',true);
    $scope.closedData = results.Where('IsOpen',false);
});
squillman
źródło
To brzmi dokładnie tak, jak mam problem. Prosta funkcja, która niczego nie aktualizowała, ale tworzyła lokalną tablicę, iterowała po jednej istniejącej tablicy $ scope, tworzyła obiekty w tablicy lokalnej i zwracała. Dzwoniąc raz i przechowując go w elemencie $ scope, rozwiązuje problem. Dzięki. Chciałbym wiedzieć, na czym polega problem z bezpośrednim użyciem metody.
AgilePro,
2

Dość późno na imprezę, ale mój problem się dział, ponieważ jest wada routera ui w kątowym 1.5.8. Warto wspomnieć, że ten błąd pojawił się tylko przy pierwszym uruchomieniu aplikacji i nie powtórzył się później. Ten post z github rozwiązał mój problem. Zasadniczo błąd polega na $urlRouterProvider.otherwise("/home") rozwiązaniu tego problemu:

$urlRouterProvider.otherwise(function($injector, $location) {
   var $state = $injector.get("$state");
   $state.go("your-state-for-home");
});
Allen
źródło
2

Na początek zignoruj ​​wszystkie odpowiedzi i powiedz, aby użyć $ watch. Angular już działa na słuchacza. Gwarantuję ci, że komplikujesz sprawy, myśląc tylko w tym kierunku.

Zignoruj ​​wszystkie odpowiedzi, które nakazują użytkownikowi $ timeout. Nie możesz wiedzieć, ile czasu zajmie ładowanie strony, dlatego nie jest to najlepsze rozwiązanie.

Musisz tylko wiedzieć, kiedy strona jest renderowana.

<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;
 }
}
});

Śledź powtórzenie ng przez $ index, a gdy długość tablicy jest równa indeksowi, zatrzymaj pętlę i wykonaj swoją logikę.

jsfiddle

Jed Lynch
źródło
1

Otrzymałem ten błąd w kontekście kontroli drzewa kątowego. W moim przypadku były to opcje drzewa. Zwracałem metodę treeOptions () z funkcji. Zawsze zwracał ten sam przedmiot. Ale Angular w magiczny sposób myśli, że jest to nowy obiekt, a następnie powoduje rozpoczęcie cyklu trawienia. Powoduje rekurencję trawień. Rozwiązaniem było powiązanie treeOptions z zakresem. I przypisz to tylko raz.

JDev
źródło
1

To dziwne ... Mam dokładnie ten sam błąd, wynikający z innej rzeczy. Podczas tworzenia kontrolera przekazałem parametr $ location, na przykład:

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

Udowodniono, że jest to błąd, gdy używamy bibliotek innych firm lub czystego JS do manipulowania niektórymi szczegółami (tutaj window.location), a następne podsumowanie angular spowoduje wyświetlenie tego błędu.

Po prostu usunąłem lokalizację $ z parametru tworzenia kontrolera i działało ponownie, bez tego błędu. Lub jeśli absolutnie potrzebujesz użyć lokalizacji $ z angular, musisz usunąć wszystkie <a href="#">link</a>linki na swojej stronie szablonu i raczej wpisać href = "" . Pracował dla mnie.

Mam nadzieję, że pewnego dnia pomoże.

Alex
źródło
0

Zdarzyło mi się to zaraz po aktualizacji Firefoksa do wersji 51. Po clearing the cachetym problem zniknął.

Zsolti
źródło
0

miałem podobny błąd, ponieważ zdefiniowałem

ng-class = "GetLink ()"

zamiast

ng-click = "GetLink ()"

Satish Kumar sonker
źródło
0

Zdarzyło mi się to po aktualizacji z kątowej 1.6 -> 1.7 podczas używania $ sce.trustAsResourceUrl () jako wartości zwracanej funkcji wywołanej z ng-src. Możesz zobaczyć ten problem, o którym mowa tutaj .

W moim przypadku musiałem zmienić następujące.

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

do

<source ng-src='{{trustedUrl}} type='video/mp4' />
trustedUrl = $sce.trustAsResourceUrl(someUrl);
aCMoFoCord
źródło
0

Otrzymałem dokładnie ten sam błąd, używając AngularJS 1.3.9, kiedy w moim niestandardowym filtrze sortowania wywołałem Array.reverse ()

Po usunięciu było dobrze.

michael hansen079
źródło