Fehler: 10 $ digest () Iterationen erreicht. Abbruch! mit dynamischem Sortby-Prädikat


134

Ich habe den folgenden Code, der den Namen des Benutzers und seine Punktzahl wiederholt und anzeigt:

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

Und der entsprechende Winkelregler.

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

Wenn ich den obigen Code ausführe, wird der Fehler angezeigt: 10 $ Digest () - Iterationen erreicht. Abbruch! Fehler in meiner Konsole.

Ich habe jsfiddle dafür erstellt.

Das Sortierprädikat wird nur innerhalb der ng-Wiederholung initialisiert und auch die Anzahl der Objekte wird begrenzt. Daher denke ich, dass es der Grund für den Fehler ist, sowohl die sortby- als auch die limitTo-Beobachter zusammen zu haben.

Wenn $ scope.reverse false ist (aufsteigende Reihenfolge der Punktzahl), tritt kein Fehler auf.

Kann mir jemand helfen zu verstehen, was hier falsch ist? Vielen Dank für Ihre Hilfe.


Wenn Sie die if-Anweisung entfernen, tritt dennoch ein Fehler auf?
Mathew Berg

Danke für deine Antwort Mathew! Ich habe das Problem falsch diagnostiziert. Das Problem scheint bei Sortby- und LimitTo-Filtern zu liegen. Ich habe die Frage mit JSFiddle aktualisiert. Vielen Dank für Ihre Hilfe.
Chubby Boy

Das ist eine eckige Sache. Sie müssen sich Ihre Funktionen merken und sich dann an den Zustand erinnern. Fangen Sie meine Antwort auf stackoverflow.com/questions/14376879/…
Julio Marins

Antworten:


116

Bitte überprüfen Sie diese jsFiddle . (Der Code ist im Grunde der gleiche, den Sie gepostet haben, aber ich verwende ein Element anstelle des Fensters, um die Bildlaufereignisse zu binden.)

Soweit ich sehen kann, gibt es kein Problem mit dem von Ihnen geposteten Code. Der von Ihnen erwähnte Fehler tritt normalerweise auf, wenn Sie eine Schleife von Änderungen über eine Eigenschaft erstellen. Beispiel: Wenn Sie nach Änderungen an einer bestimmten Eigenschaft suchen und dann den Wert dieser Eigenschaft im Listener ändern:

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

Dies führt zu einer Fehlermeldung:

Nicht erfasster Fehler: 10 $ Digest () - Iterationen erreicht. Abbruch!
Beobachter feuerten in den letzten 5 Iterationen: ...

Stellen Sie sicher, dass Ihr Code keine solchen Situationen aufweist.

aktualisieren:

Das ist Dein Problem:

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

Sie sollten Objekte / Modelle während des Renderns oder auf andere Weise nicht ändern, da dies ein neues Rendern erzwingt (und folglich eine Schleife , die die 'Fehler: 10 $ Digest () - Iterationen erreicht. Abbrechen!' ).

Wenn Sie das Modell aktualisieren möchten, tun Sie dies auf dem Controller oder in einer Direktive, niemals in der Ansicht. AngularJS Dokumentation empfiehlt nicht zu verwenden , die ng-initgenau diese Art von Situationen zu vermeiden:

Verwenden Sie die ngInit-Direktive in Vorlagen (nur für Spielzeug- / Beispiel-Apps, nicht für echte Anwendungen empfohlen).

Hier ist eine jsFiddle mit einem funktionierenden Beispiel.


1
Zu angular.element(w).bind()Ihrer Information, anstatt Sie können verwenden element.bind().
Mark Rajcok

Vielen Dank bmleite und Mark. Ich habe das Problem falsch diagnostiziert. Bitte beachten Sie meine Kommentare oben. Ich habe die Frage mit JSFiddle aktualisiert. Vielen Dank für Ihre Hilfe.
Chubby Boy

Vielen Dank @bmleite! Ich versuche nur mehr zu verstehen. Aber warum ist das so, wenn $ scope.reverse = false (aufsteigende Reihenfolge der Punktzahl) keinen Fehler verursacht?
Chubby Boy

Für aufsteigend und absteigend sollten Sie die Präfixe '+' und '-' verwenden (dh '+ score' und '-score'). Weitere Informationen dazu hier .
Bmleite

1
Diese Antwort hat mein Problem gelöst. Die Erklärung ist insofern gut, als sie das Problem beschreibt: Der Iterationsfehler $ Digest () tritt auf, wenn Sie versuchen, eine Eigenschaft zu ändern, während Sie sie durchlaufen. Jede Eigenschaftsänderung löst also eine Aktualisierung der Ansicht (UI) aus, und der Winkel wird schließlich bei 10 Schleifen maximal. Im Beispiel jsFiddle wird die Eigenschaftsänderung in den Controller eingefügt. Das Ändern der Eigenschaft in der Ansicht führt zu diesem Fehler.
Mbokil

9

Die Ursache für diesen Fehler war für mich ...

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

in meiner Vorlage

Dadurch wird die Funktion myTrustSrc in meinem Controller in einer Endlosschleife aufgerufen. Wenn ich das ng-if aus dieser Zeile entferne, ist das Problem gelöst.

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

Die Funktion wird nur einige Male aufgerufen, wenn ng-if nicht verwendet wird. Ich frage mich immer noch, warum die Funktion mit ng-src mehrmals aufgerufen wird.

Dies ist die Funktion in der Steuerung

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

Ich frage mich immer noch, warum die Funktion mit ng-src mehrmals aufgerufen wird. - weil Angular einige Male versucht, das HTML zu erstellen, bis 2 identische Ergebnisse erzielt werden. das ist die Bedeutung des Fehlers 10 $ Digest () Iterationen erreicht, versuchte er 10 Mal und bekam nie 2 identische Ergebnisse
Bresleveloper

@bresleveloper Könnten Sie einen Link mit diesen Informationen bereitstellen? Vielen Dank.
Willa

@Willa siehe hier docs.angularjs.org/api/ng/type/$rootScope.Scope CTRF + F this "Das Wiederholungs-Iterationslimit beträgt 10, um einen Deadlock der Endlosschleife zu verhindern"
bresleveloper

Vielen Dank. Das hat geholfen.
Willa

7

Für mich war es so, dass ich ein Funktionsergebnis als 2-Wege-Bindungseingabe '=' an eine Direktive übergab, die jedes Mal ein neues Objekt erstellte.

also hatte ich so etwas:

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

und die Controller-Methode auf my-dir war

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

was als ich gemacht habe

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

Problem gelöst!

Hoffentlich hilft das jemandem :)


5

Ich habe ein anderes Beispiel für etwas, das dies verursacht hat. Hoffentlich hilft es als zukünftige Referenz. Ich verwende AngularJS 1.4.1.

Ich hatte dieses Markup mit mehreren Aufrufen einer benutzerdefinierten Direktive:

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

myDataist ein Array und Where()eine Erweiterungsmethode, die über das Array iteriert und ein neues Array zurückgibt, das alle Elemente aus dem Original enthält, wobei die IsOpen-Eigenschaft mit dem Bool-Wert im zweiten Parameter übereinstimmt.

In der Steuerung habe ich so eingestellt $scope.data:

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

Where()Das Problem war das Aufrufen der Erweiterungsmethode aus der Direktive wie im obigen Markup. Um dieses Problem zu beheben, habe ich den Aufruf der Erweiterungsmethode anstelle des Markups in den Controller verschoben:

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

und der neue Controller-Code:

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

Das klingt genau nach dem Problem, das ich habe. Eine einfache Funktion, die nichts aktualisiert, sondern ein lokales Array erstellt, über ein vorhandenes $ scope-Array iteriert, Objekte im lokalen Array erstellt und zurückgegeben hat. Durch einmaliges Aufrufen und Speichern in einem $ scope-Mitglied wird das Problem gelöst. Vielen Dank. Ich wünschte, ich wüsste, was das Problem bei der direkten Verwendung der Methode ist.
AgilePro

2

Ziemlich spät zur Party, aber mein Problem trat auf, weil es einen Defekt im UI-Router in Winkel 1.5.8 gibt. Zu erwähnen ist, dass dieser Fehler nur beim ersten Ausführen der Anwendung aufgetreten ist und danach nicht mehr auftritt. Dieser Beitrag von Github hat mein Problem gelöst. Grundsätzlich besteht der Fehler darin, dass $urlRouterProvider.otherwise("/home") die Lösung eine Problemumgehung wie die folgende war:

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

2

Ignorieren Sie zunächst alle Antworten mit der Aufforderung, $ watch zu verwenden. Angular arbeitet bereits mit einem Hörer. Ich garantiere Ihnen, dass Sie die Dinge komplizieren, indem Sie nur in diese Richtung denken.

Ignorieren Sie alle Antworten, die Sie dem Benutzer $ timeout mitteilen. Sie können nicht wissen, wie lange das Laden der Seite dauern wird, daher ist dies nicht die beste Lösung.

Sie müssen nur wissen, wann das Rendern der Seite abgeschlossen ist.

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

Verfolgen Sie die ng-Wiederholung durch $ index und wenn die Länge des Arrays gleich dem Index ist, stoppen Sie die Schleife und führen Sie Ihre Logik aus.

jsfiddle


1

Ich habe diesen Fehler im Zusammenhang mit der Winkelbaumsteuerung erhalten. In meinem Fall waren es die Baumoptionen. Ich habe treeOptions () von einer Funktion zurückgegeben. Es wurde immer das gleiche Objekt zurückgegeben. Aber Angular denkt auf magische Weise, dass es sich um ein neues Objekt handelt, und startet dann einen Verdauungszyklus. Rekursion von Digests verursachen. Die Lösung bestand darin, die treeOptions an den Bereich zu binden. Und weisen Sie es nur einmal zu.


1

Es ist komisch ... Ich habe genau den gleichen Fehler, der von einer anderen Sache herrührt. Beim Erstellen meines Controllers habe ich den Parameter $ location wie folgt übergeben:

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

Dies hat sich als Fehler erwiesen, wenn wir Bibliotheken von Drittanbietern oder reines JS verwenden, um einige Details zu manipulieren (hier window.location). Der nächste Digest von Angular wird diesen Fehler auslösen.

Also habe ich einfach die Position $ aus dem Parameter für die Controller-Erstellung entfernt und es hat wieder funktioniert, ohne diesen Fehler. Oder wenn Sie unbedingt die Position $ aus dem Winkel verwenden müssen, müssen Sie jeden einzelnen <a href="#">link</a>in den Links Ihrer Vorlagenseite entfernen und stattdessen href = "" schreiben . Hat für mich gearbeitet.

Hoffe es kann eines Tages helfen.



0

Dies passierte mir direkt nach dem Upgrade von Firefox auf Version 51. Danach clearing the cacheist das Problem behoben.


0

Ich hatte den ähnlichen Fehler, weil ich definiert hatte

ng-class = "GetLink ()"

anstatt

ng-click = "GetLink ()"


0

Dies geschah mir nach dem Upgrade von Angular 1.6 -> 1.7, wenn $ sce.trustAsResourceUrl () als Rückgabewert einer von ng-src aufgerufenen Funktion verwendet wurde. Sie können dieses hier erwähnte Problem sehen .

In meinem Fall musste ich Folgendes ändern.

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

zu

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.