エラー:10回の$ digest()反復に達しました。中止します!動的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'}]
}

上記のコードを実行すると、エラーが発生します:10回の$ digest()反復に達しました。中止します!コンソールのエラー。

同じためにjsfiddleを作成しました。

並べ替えの述語はng-repeat内でのみ初期化されており、オブジェクトの数にも制限が適用されています。だから、sortbyとlimitToの両方のウォッチャーを一緒に持つことがエラーの理由だと思います。

$ scope.reverseがfalse(スコアの昇順)の場合、エラーにはなりません。

誰かが私がここで何が間違っているかを理解するのを手伝ってくれる?あなたの助けに感謝します。


ifステートメントを削除しても、エラーは発生しますか?
Mathew Berg

マシューの回答ありがとうございます!問題を間違って診断しました。問題は、sortbyフィルターとlimitToフィルターにあるようです。JSFiddleで質問を更新しました。あなたの助けに感謝します。
チャビーボーイ

これは角度のあるものです。自分の機能をメモして、その状態を覚えておく必要があります。stackoverflow.com/questions/14376879/…で
Julio Marins

回答:


116

このjsFiddleを確認してください。(コードは基本的にあなたが投稿したものと同じですが、スクロールイベントをバインドするためにウィンドウの代わりに要素を使用しています)。

私の知る限り、投稿したコードに問題はありません。あなたが言及したエラーは通常、プロパティに対して変更のループを作成するときに発生します。たとえば、特定のプロパティの変更を監視し、リスナーでそのプロパティの値を変更する場合などです。

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

これにより、エラーメッセージが表示されます。

キャッチされないエラー:10回の$ digest()反復に達しました。中止します!
ウォッチャーは、過去5回の反復で発砲しました:...

コードにこのような状況がないことを確認してください。

更新:

これはあなたの問題です:

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

レンダー中にオブジェクト/モデルを変更しないでください。そうしないと、新しいレンダーが強制されます(その結果、ループが発生し、「エラー:10回の$ digest()の反復に到達しました。中止します!」)。

モデルを更新する場合は、コントローラーまたはディレクティブで行います。ビューでは行わないでください。angularjsのドキュメントでng-init次のような状況を避けるためにを正確に使用ないことを推奨しています

テンプレートでngInitディレクティブを使用します(おもちゃ/サンプルアプリのみ、実際のアプリケーションには推奨されません)

ここだjsFiddle実施例では。


1
参考までに、代わりにangular.element(w).bind()を使用できますelement.bind()
Mark Rajcok 2013年

bmleiteとMarkに感謝します。問題を間違って診断しました。上記のコメントをご覧ください。JSFiddleで質問を更新しました。あなたの助けに感謝します。
チャビーボーイ、

@bmleite、ありがとうございました!もっと理解しようとしています。しかし、なぜ$ scope.reverse = false(スコアの昇順)でエラーが発生しないのですか?
チャビーボーイ

昇順と降順では、それぞれ接頭辞「+」と「-」を使用する必要があります(つまり、「+ score」と「-score」)。この詳細については、こちらをご覧ください
bmleite 2013年

1
この答えは私の問題を解決しました。説明は問題を説明している点で優れています。ループしているときに同時にプロパティを変更しようとすると、$ digest()反復エラーが発生します。したがって、各プロパティの変更はビュー(UI)の更新をトリガーし、角度は最終的に10ループで最大になります。jsFiddleの例では、プロパティの変更をコントローラーに入れます。ビューでプロパティを変更すると、このエラーが発生します。
mbokil 2013年

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で関数が2回以上呼び出されるのはなぜですか?

これはコントローラーの機能です

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

ng-srcで関数が2回以上呼び出されるのはなぜですか?-angularは、同じ2つの結果が得られるまで、htmlを数回作成しようとするためです。これは、10回の$ digest()反復に到達したエラーの意味です。彼は10回試行しましたが、2つの同じ結果が得られませんでした
bresleveloper

@bresleveloperにこの情報へのリンクを提供していただけますか?ありがとう。
Willa

@Willaこちらをご覧くださいdocs.angularjs.org/api/ng/type/$rootScope.Scope CTRF + F this "無限ループデッドロックを防ぐために再実行の反復制限は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プロパティが2番目のパラメーターの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);
});

それは私が抱えている問題のように聞こえます。何も更新せずにローカル配列を作成し、1つの既存の$ scope配列を反復処理し、ローカル配列にオブジェクトを作成して返す単純な関数。1回呼び出して$ scopeメンバーに格納することで、問題を解決します。ありがとう。メソッドを直接使用することの問題が何であるかを知りたいと思います。
AgilePro

2

パーティーにはかなり遅れましたが、角度1.5.8のui-routerに欠陥があるため、私の問題が発生していました。言及すべきことは、このエラーはアプリケーションを初めて実行したときにのみ発生し、その後は再発しないことです。 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;
 }
}
});

$ indexによってng-repeatを追跡し、配列の長さがインデックスと等しい場合、ループを停止してロジックを実行します。

jsfiddle


1

角度ツリー制御のコンテキストでこのエラーが発生しました。私の場合、それはツリーオプションでした。関数からtreeOptions()を返していました。常に同じオブジェクトを返していました。しかし、Angularは魔法のように新しいオブジェクトであると考え、ダイジェストサイクルを開始します。ダイジェストの再帰を引き起こします。解決策は、treeOptionsをスコープにバインドすることでした。そして、それを一度だけ割り当てます。


1

それは奇妙です...私はまったく同じエラーを持っています、別のものから来ています。コントローラを作成するときに、次のように$ locationパラメータを渡しました。

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

これは、 サードパーティのライブラリまたは純粋なJSを使用していくつかの詳細(ここではwindow.location)を操作するときにバグであることが判明し、次の角度のダイジェストでこのエラーが発生します。

そのため、コントローラーの作成パラメーターから$ locationを削除するだけで、このエラーは発生せずに再び機能しました。または、絶対に$ locationをangularから使用する必要がある場合<a href="#">link</a>は、テンプレートページのリンクからすべてを削除し、href = ""と記述する必要があります。私のために働いた。

それが一日に役立つことを願っています。



0

これは、Firefoxをバージョン51にアップグレードした直後に起こりましclearing the cacheた。その後、問題は解決しました。



0

これは、ng-srcから呼び出された関数の戻り値として$ sce.trustAsResourceUrl()を使用している場合、angular 1.6-> 1.7からアップグレードした後に発生しました。あなたはここで言及されたこの問題を見ることができます

私の場合、以下を変更する必要がありました。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.