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。ありがとう