Erro: 10 iterações $ digest () atingidas. Abortando! com predicado sortby dinâmico

134

Eu tenho o seguinte código que repete e exibe o nome do usuário e sua pontuação:

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

E o controlador angular correspondente.

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

Quando executo o código acima, recebo as iterações Error: 10 $ digest () atingidas. Abortando! erro no meu console.

Eu criei o jsfiddle para o mesmo.

O predicado de classificação está sendo inicializado apenas dentro do ng-repeat e também o limite está sendo aplicado no número de objetos. por isso, sinto que ter tanto o sortby quanto o limitTo observadores juntos é a razão do erro.

Se o $ scope.reverse for falso (ordem crescente de pontuação), não haverá erro.

Alguém pode me ajudar a entender o que está errado aqui? Aprecio muito sua ajuda.

Menino gordinho
fonte
Se você remover a instrução if, isso ainda ocorre?
Mathew Berg
Obrigado pela sua resposta Mathew! Eu diagnóstico o problema incorretamente. O problema parece estar nos filtros sortby e limitTo. Atualizei a pergunta com o JSFiddle. Aprecio muito sua ajuda.
amigos estão dizendo sobre chubby boy
isso é uma coisa angular. Você precisa memorizar suas funções e lembrar-se do estado. Pegue minha resposta em stackoverflow.com/questions/14376879/…
Julio Marins

Respostas:

116

Por favor, verifique este jsFiddle . (O código é basicamente o mesmo que você postou, mas eu uso um elemento em vez da janela para vincular os eventos de rolagem).

Tanto quanto posso ver, não há nenhum problema com o código que você postou. O erro que você mencionou normalmente ocorre quando você cria um loop de alterações em uma propriedade. Por exemplo, como quando você observa alterações em uma determinada propriedade e altera o valor dessa propriedade no ouvinte:

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

Isso resultará em uma mensagem de erro:

Erro não capturado: 10 iterações $ digest () atingidas. Abortando!
Observadores dispararam nas últimas 5 iterações: ...

Verifique se o seu código não possui esse tipo de situação.

atualizar:

Isso é problema seu:

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

Você não deve alterar objetos / modelos durante a renderização ou de outra forma, ela forçará uma nova renderização (e consequentemente um loop , que causa as iterações 'Error: 10 $ digest () atingidas. Abortando!' ).

Se você deseja atualizar o modelo, faça-o no Controlador ou em uma Diretiva, nunca na vista. A documentação do angularjs recomenda não usarng-init exatamente o que é necessário para evitar esses tipos de situações:

Use a diretiva ngInit em modelos (apenas para aplicativos de brinquedo / exemplo, não recomendado para aplicativos reais)

Aqui está um jsFiddle com um exemplo de trabalho.

bmleite
fonte
1
FYI, em vez de angular.element(w).bind()você pode usar element.bind().
Mark Rajcok
Muito obrigado bmleite e Mark. Eu diagnóstico o problema incorretamente. Por favor, veja meus comentários acima. Atualizei a pergunta com o JSFiddle. Aprecio muito sua ajuda.
Chubby Boy
Muito obrigado @bmleite! Apenas tentando entender mais. Mas por que isso se $ scope.reverse = false (ordem crescente de pontuação) não causa erro?
Chubby Boy
Para subir e descer, você deve usar os prefixos '+' e '-', respectivamente (ou seja, '+ score' e '-score'). Mais informações aqui .
bmleite
1
Esta resposta resolveu meu problema. A explicação é boa, pois descreve o problema: o erro de iterações $ digest () ocorre quando você tenta modificar uma propriedade ao mesmo tempo em que faz o loop. Portanto, cada alteração de propriedade aciona uma atualização da visualização (UI) e angular acaba no máximo em 10 loops. O exemplo jsFiddle coloca a alteração de propriedade no Controller. Alterar a propriedade na exibição resulta nesse erro.
mbokil
9

A causa desse erro para mim foi ...

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

no meu modelo

Faz com que a função myTrustSrc no meu controlador seja chamada em um loop infinito. Se eu remover o ng-if dessa linha, o problema será resolvido.

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

A função é chamada apenas algumas vezes quando ng-if não é usado. Ainda me pergunto por que a função é chamada mais de uma vez com ng-src?

Esta é a função no controlador

$scope.myTrustSrc = function(src) {
    return $sce.trustAsResourceUrl(src);
}
Natus Drew
fonte
Ainda me pergunto por que a função é chamada mais de uma vez com ng-src? - porque angular tenta criar o html algumas vezes até obter 2 resultados idênticos. Esse é o significado do erro de US $ 10 digerir () iterações atingido, ele tentou 10 vezes e nunca recebi 2 resultados idênticos
bresleveloper
@bresleveloper você poderia fornecer um link com essas informações? Obrigado.
Willa
@Willa olha aqui docs.angularjs.org/api/ng/type/$rootScope.Scope CTRF + F este "O limite de iteração reprise é de 10 para evitar um impasse loop infinito"
bresleveloper
Obrigado. Isso ajudou.
Willa
7

Para mim, estava passando um resultado de função como entrada de ligação bidirecional '=' para uma diretiva que criava um novo objeto todas as vezes.

então eu tinha algo assim:

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

e o método do controlador em my-dir foi

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

que quando eu fiz

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

resolveu o problema!

Espero que isso ajude alguém :)

Michail Michailidis
fonte
5

Eu tenho outro exemplo de algo que causou isso. Espero que ajude para referência futura. Estou usando o AngularJS 1.4.1.

Eu tive essa marcação com várias chamadas para uma diretiva personalizada:

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

myDataé uma matriz e Where()é um método de extensão que itera sobre a matriz, retornando uma nova matriz que contém itens do original onde a propriedade IsOpen corresponde ao valor bool no segundo parâmetro.

No controlador, defino $scope.dataassim:

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

Chamar o Where()método de extensão da diretiva como na marcação acima foi o problema. Para corrigir esse problema, movi a chamada para o método de extensão para o controlador em vez da marcação:

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

e o novo código do controlador:

DataService.getData().then(function(results){
    $scope.openData = results.Where('IsOpen',true);
    $scope.closedData = results.Where('IsOpen',false);
});
squillman
fonte
Isso soa exatamente como o problema que tenho. Uma função simples que não atualizou nada, mas criou uma matriz local, iterou sobre uma matriz existente de $ scope, criou objetos na matriz local e retornou. Ao ligar uma vez e armazená-lo em um membro $ scope, ele resolve o problema. Obrigado. Gostaria de saber qual é o problema de usar o método diretamente.
AgilePro
2

Muito tarde para a festa, mas meu problema estava acontecendo porque há um defeito no roteador da interface do usuário no angular 1.5.8. Uma coisa a mencionar é que esse erro apareceu apenas na primeira vez em que eu estava executando o aplicativo e não ocorreu novamente depois. Esta postagem do github resolveu meu problema. Basicamente, o erro envolve $urlRouterProvider.otherwise("/home") A solução foi uma solução alternativa como esta:

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

Para iniciantes, ignore todas as respostas com diga para usar $ watch. O Angular já funciona com um ouvinte. Eu garanto que você está complicando as coisas apenas pensando nessa direção.

Ignore todas as respostas que dizem ao usuário $ timeout. Você não pode saber quanto tempo a página levará para carregar, portanto, essa não é a melhor solução.

Você só precisa saber quando a página termina de renderizar.

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

Acompanhe o ng-repeat por $ index e quando o comprimento da matriz for igual ao índice pare o loop e faça sua lógica.

jsfiddle

Jed Lynch
fonte
1

Eu recebi esse erro no contexto do controle de árvore angular. No meu caso, foram as opções de árvore. Eu estava retornando treeOptions () de uma função. Sempre retornava o mesmo objeto. Mas Angular pensa magicamente que esse é um novo objeto e, em seguida, causa um ciclo de digestão. Causando uma recursão de resumos. A solução foi vincular as treeOptions ao escopo. E atribuí-lo apenas uma vez.

JDev
fonte
1

É estranho ... Eu tenho exatamente o mesmo erro, vindo de uma coisa diferente. Quando crio meu controlador, passei o parâmetro $ location, assim:

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

Isso provou ser um bug quando usamos bibliotecas de terceiros ou JS puro para manipular algumas especificidades (aqui window.location). O próximo resumo do angular irá causar esse erro.

Então, simplesmente removi o local $ do parâmetro de criação do controlador e ele funcionou novamente, sem esse erro. Ou, se você absolutamente precisar usar o local $ do angular, remova todos <a href="#">link</a>os links da página do seu modelo e escreva href = "" . Trabalhou para mim.

Espero que possa ajudar um dia.

Alex
fonte
0

Isso aconteceu comigo após a atualização do Firefox para a versão 51. Depois clearing the cache, o problema desapareceu.

Zsolti
fonte
0

eu tive o erro semelhante, porque eu tinha definido

ng-class = "GetLink ()"

ao invés de

ng-click = "GetLink ()"

Satish Kumar sonker
fonte
0

Isso aconteceu comigo após a atualização do angular 1.6 -> 1.7 ao usar $ sce.trustAsResourceUrl () como o valor de retorno de uma função chamada ng-src. Você pode ver esse problema mencionado aqui .

No meu caso, tive que mudar o seguinte.

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

para

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

Eu recebi exatamente o mesmo erro usando o AngularJS 1.3.9 quando, no meu filtro de classificação personalizado, invoquei Array.reverse ()

Depois que eu o removi, tudo ficou bem.

michael hansen079
fonte