web-dev-qa-db-fra.com

Erreur: 10 $ digest () itérations atteintes. Abandonner! avec prédicat de tri dynamique

J'ai le code suivant qui répète et affiche le nom de l'utilisateur et son score:

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

Et le contrôleur angulaire correspondant.

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

Lorsque je lance le code ci-dessus, je reçois le Error: 10 $ digest () itérations atteintes. Abandonner! erreur dans ma console. 

J'ai créé jsfiddle pour les mêmes. 

Le prédicat de tri est initialisé uniquement dans la répétition ng et la limite est également appliquée au nombre d'objets. Je pense donc que la raison de l'erreur est d'avoir à la fois les observateurs triés et limités.

Si $ scope.reverse est faux (ordre croissant des scores), alors il ne commet pas d'erreur.

Quelqu'un peut-il m'aider à comprendre ce qui ne va pas ici? J'apprécie beaucoup votre aide.

131
Sabarish Sankar

Veuillez vérifier ceci jsFiddle . (Le code est fondamentalement le même que vous avez posté, mais j'utilise un élément au lieu de la fenêtre pour lier les événements de défilement).

Autant que je sache, le code que vous avez publié ne pose aucun problème. L'erreur que vous avez mentionnée se produit normalement lorsque vous créez une boucle de modifications sur une propriété. Par exemple, comme lorsque vous surveillez les modifications apportées à une propriété donnée, puis que vous modifiez la valeur de cette propriété sur l'écouteur:

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

Cela entraînera un message d'erreur: 

Erreur non capturée: 10 itérations $ digest () atteintes. Abandonner!
Observateurs tiré dans les 5 dernières itérations: ...

Assurez-vous que votre code ne présente pas ce genre de situation.

mettre à jour:

C'est ton problème: 

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

Vous ne devriez pas changer d'objets ou de modèles pendant le rendu ou autrement, cela forcerait un nouveau rendu (et par conséquent une boucle), ce qui entraînerait la 'Erreur: 10 itérations $ digest () atteintes. Abandon ! ').

Si vous souhaitez mettre à jour le modèle, faites-le sur le contrôleur ou sur une directive, jamais sur la vue. angularjs documentation recommande de ne pas utiliser le ng-init exactement pour éviter ce genre de situation:

Utilisez la directive ngInit dans les modèles (pour les applications jouets/exemples uniquement, pas Recommandé pour les applications réelles)

Voici un jsFiddle avec un exemple de travail.

110
bmleite

La cause de cette erreur pour moi était ...

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

dans mon modèle

La fonction myTrustSrc de mon contrôleur est appelée dans une boucle sans fin. Si je supprime le ng-if de cette ligne, le problème est résolu.

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

La fonction n'est appelée que quelques fois lorsque ng-if n'est pas utilisé. Je me demande encore pourquoi la fonction s'appelle plus d'une fois avec ng-src?

C'est la fonction dans le contrôleur

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

J'ai un autre exemple de quelque chose qui a causé cela. Espérons que cela aide pour référence future. J'utilise AngularJS 1.4.1.

J'avais ce balisage avec plusieurs appels à une directive personnalisée:

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

myData est un tableau et Where() est une méthode d'extension qui parcourt le tableau, renvoyant un nouveau tableau contenant les éléments de l'original où la propriété IsOpen correspond à la valeur bool du second paramètre.

Dans le contrôleur, je place $scope.data comme ceci:

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

Le problème était l'appel de la méthode d'extension Where() à partir de la directive, comme dans le balisage précédent. Pour résoudre ce problème, j'ai déplacé l'appel vers la méthode d'extension dans le contrôleur au lieu du balisage:

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

et le nouveau code du contrôleur:

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

Pour moi, c’était que je passais un résultat de fonction en tant qu’entrée de liaison bidirectionnelle '=' à une directive qui créait chaque fois un nouvel objet.

donc j'avais quelque chose comme ça:

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

et la méthode du contrôleur sur my-dir était

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

qui quand j'ai fait pour 

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

résolu le problème!

Espérons que cela aidera quelqu'un :)

4

Pour commencer, ignorez toutes les réponses avec vous dire d'utiliser $ watch. Angular fonctionne déjà chez un auditeur. Je vous garantis que vous compliquez les choses en pensant simplement dans cette direction.

Ignore toutes les réponses qui indiquent à l'utilisateur $ timeout. Vous ne pouvez pas savoir combien de temps la page mettra à charger, donc ce n'est pas la meilleure solution.

Vous avez seulement besoin de savoir quand la page est terminée.

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

Suivre le ng-repeat par $ index et lorsque la longueur du tableau est égale à l'index, arrêtez la boucle et faites votre logique.

jsfiddle

2
Jed Lynch

J'ai eu cette erreur dans le contexte du contrôle d'arbre angulaire . Dans mon cas, c'était les options de l'arbre. Je retournais treeOptions () à partir d'une fonction. Il retournait toujours le même objet. Mais Angular pense comme par magie que c'est un nouvel objet et ensuite déclencher un cycle de digestion. Causer une récursion de digests. La solution consistait à lier l’arborescence à la portée. Et attribuez-le juste une fois. 

1
JDev

Assez tard pour la soirée mais mon problème se posait car il y avait un défaut dans ui-router dans 1.5.8 angulaire. Une chose à mentionner est que cette erreur est apparue seulement la première fois que j'exécutais l'application et qu'elle ne se reproduirait plus par la suite . Ce message de github a résolu mon problème . En gros, l'erreur implique $urlRouterProvider.otherwise("/home").__ La solution était une solution de contournement comme celle-ci:

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

C'est bizarre ... J'ai exactement la même erreur, venant d'une chose différente. Lorsque j'ai créé mon contrôleur, j'ai passé le paramètre $ location, comme ceci: 

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

Cela s’est avéré être un bug Lorsque nous utilisons des bibliothèques tierces ou du JS pur pour manipuler certains détails (ici window.location), le prochain condensé d’angular annulera cette erreur.

J'ai donc simplement supprimé $ location du paramètre de création du contrôleur, et cela a fonctionné à nouveau, sans cette erreur . Ou, si vous devez absolument utiliser $ location de angular, vous devez supprimer chaque <a href="#">link</a> dans. les liens de votre page de modèle et écrivez plutôt href = "". Travaillé pour moi.

J'espère que ça peut aider un jour.

1
Alex

Cela m'est arrivé juste après la mise à niveau de Firefox vers la version 51. Après clearing the cache, le problème a disparu.

0
Zsolti

Si vous utilisez angular, supprimez le profil ng-storage de la console de votre navigateur .

Dans Chrome F12-> Ressources-> Stockage local

0
David Donari

j'ai eu l'erreur similaire, parce que j'avais défini 

ng-class = "GetLink ()"

au lieu de 

ng-click = "GetLink ()"

0

Cela m'est arrivé après la mise à niveau d'angle 1.6 -> 1.7 lorsque $ sce.trustAsResourceUrl () a été utilisé comme valeur de retour d'une fonction appelée depuis ng-src. Vous pouvez voir cette question mentionnée ici .

Dans mon cas, j'ai dû changer ce qui suit.

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