divを繰り返し作成したいのですが、アイテムは関数によって返されるオブジェクトです。ただし、次のコードはエラーを報告します。$ digest()の反復が10回に達しました。中止します!jsfiddleはこちら:http ://jsfiddle.net/BraveOstrich/awnqm/
<body ng-app>
<div ng-repeat="entity in getEntities()">
Hello {{entity.id}}!
</div>
</body>
divを繰り返し作成したいのですが、アイテムは関数によって返されるオブジェクトです。ただし、次のコードはエラーを報告します。$ digest()の反復が10回に達しました。中止します!jsfiddleはこちら:http ://jsfiddle.net/BraveOstrich/awnqm/
<body ng-app>
<div ng-repeat="entity in getEntities()">
Hello {{entity.id}}!
</div>
</body>
回答:
短い答え:本当にそのような機能が必要ですか、それともプロパティを使用できますか?http://jsfiddle.net/awnqm/1/
長い答え
簡単にするために、オブジェクトの配列のngRepeatについてのみ説明します。また、詳細は省略します。
AngularJSはダーティチェックを使用して変更を検出します。アプリケーションが起動すると、それが実行さ$digestれ$rootScopeます。スコープの階層の$digest深さ優先トラバーサルを行います。すべてのスコープに時計のリストがあります。各時計には最後の値があります(最初はinitWatchVal)。すべてのウォッチのスコープごとに$digest実行し、現在の値(watch.get(scope))を取得してと比較しwatch.lastます。現在の値がwatch.last(常に最初の比較で)等しくない場合は、に$digest設定さdirtyれtrueます。からすべてのスコープが処理される場合、dirty == true $digestから別の深さ優先トラバーサルが開始され$rootScopeます。$digestダーティ== falseまたはトラバーサルの数== 10で終了します。後者の場合、エラー「10 $ digest()反復に達しました」。ログに記録されます。
今についてngRepeat。watch.get呼び出しごとに、コレクションからのオブジェクト(の値を返すgetEntities)と追加情報を(HashQueueMapによってhashKey)キャッシュに保存します。すべてのwatch.get呼び出しで、キャッシュからngRepeatオブジェクトを取得しようとしますhashKey。それは、キャッシュに存在しない場合はngRepeat新しいスコープを作成し、プットがそれにオブジェクトをキャッシュに格納し、DOM要素、作成など。
今についてhashKey。通常hashKeyはによって生成される一意の番号nextUid()です。しかし、それは機能することができます。hashKey将来の使用のために生成した後、オブジェクトに格納されます。
例でエラーが発生する理由:関数はgetEntities()常に新しいオブジェクトの配列を返します。このオブジェクトはキャッシュにhashKey存在せず、ngRepeatキャッシュにも存在しません。したがってngRepeat、それぞれwatch.getがの新しいウォッチを使用して、そのスコープを生成し{{entity.id}}ます。この時計は最初にwatch.get持っていwatch.last == initWatchValます。ですからwatch.get() != watch.last。だから、$digest新しいトラバースを開始します。だから、ngRepeat新しい時計を持つ新しいスコープを作成します。したがって、10回のトラバースの後、エラーが発生します。
それを修正する方法
getEntities()呼び出しで新しいオブジェクトを作成しないでください。hashKey、それらのメソッドを追加できます。例については、このトピックを参照してください。AngularJSの内部を知っている人が、私が何か間違っている場合は修正してくれるといいのですが。
Do not create new objects on every getEntities() call.:それはこのように、かなり簡単に固定することができます<div ng-repeat="entity in entities = (entities || getEntities())">
getEntities()常に同じ配列を返す場合に機能します。配列が変更された場合、それはng-repeat
繰り返しの外で配列を初期化する
<body ng-app>
<div ng-init="entities = getEntities()">
<div ng-repeat="entity in entities">
Hello {{entity.id}}!
</div>
</div>
</body>
getEntities()プログラムのライフサイクルでが何か異なるものを返す場合、これは機能しません。たとえば、それがをgetEntities()トリガーするとし$http.getます。getが最終的に解決されたとき(AJAX呼び出しを行ったとき)は、entitiesすでに初期化されています。
The only appropriate use of ngInit is for aliasing special properties of ngRepeat. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
ゲッターはべき等ではなく、モデルが変更されます(呼び出されるたびに新しい配列が生成されます)。これにより、angularはモデルが最終的に安定することを期待してそれを呼び出し続けますが、angularは決してあきらめず、例外をスローします。
ゲッターが返す値は同じですが同一ではなく、それが問題です。
アレイをメインコントローラの外に移動すると、この動作がなくなることがわかります。
var array = [{id:'angularjs'}];
function Main($scope) {
$scope.getEntities = function(){return array;};
};
今は毎回同じオブジェクトを返すからです。関数ではなくスコープのプロパティを使用するには、モデルを再構築する必要がある場合があります。
コントローラーのメソッドの結果をプロパティに割り当て、それに対してng:repeatを実行することで回避しました。
@prznoコメントに基づく
<body ng-app>
<div ng-repeat="item in t = angular.equals(t, getEntities()) ? t : getEntities()">
Hello {{item.id}}!
</div>
</body>
BTWの2番目のソリューション@Artem Andreevは、Angular 1.1.4以降では機能しないことを示唆していますが、最初のソリューションは問題を解決しません。だから、私は今のところ恐れていますが、これは機能に不利な点のないスパイクの少ないソリューションです
Item.idそれがすべきことですb。ありがとう