web-dev-qa-db-ja.com

配列の更新時にAngularJSがngRepeatを更新しない

私は時々AngularJSを理解するのに深刻な問題を抱えています。だから私は私のコントローラのような基本的な配列を持っています

$scope.items = ["a","b","c"]

私は、テンプレートで項目配列ng-repeat = "item in items"をngRepeatingしています。これまでのところ非常にまっすぐです。 UXアクションを数回実行した後、新しいものをアレイにプッシュします。

 $scope.items.Push("something");

そのため、50%の時間、新しい要素がビューに追加されます。しかし、残りの50%は何も起こりません。そして、それはとてもイライラするようなものです。 bc $ scope。$ apply()内でラップすると、「$ digest already in progress」エラーが発生しました。それを$ timeoutにラップすることも役に立ちません。

そして、Chrome拡張機能を使用して要素スコープを検査すると、新しいデータが存在し、$ scope.items値が正しいことがわかります。 DOMに。

ありがとう!

31
spacenick

角度の50%の$digestサイクルの外側でスコープを変更しています。

Anglejsからではないコールバックがある場合; (おそらくjquery)。 $applyサイクルを強制するには、$digestを呼び出す必要があります。ただし、$applyサイクル中に$digestを呼び出すことはできません。変更はすべて自動的に反映されるためです。

コールバックがangularからではなく、$applyを呼び出す必要がある場合はいつかを知る必要があります。

あなたが知らないで学ぶことができない場合、ここにきちんとしたトリックがあります:

var applyFn = function () {
    $scope.someProp = "123";
};
if ($scope.$$phase) { // most of the time it is "$digest"
    applyFn();
} else {
    $scope.$apply(applyFn);
}
21
Umur Kontacı

UmurKontacıが指摘したように、ダイジェストサイクル以外でモデルを変更することもあります。ただし、この問題を回避して、適用/ダイジェストコンテキストにあるかどうかを検出しようとする代わりに、これが発生しないことを確認することをお勧めします。

この問題の主な原因は、関数がDOMイベントへの反応として呼び出されることです。例えば。

jQuery('.some-element').click(function() { seeminglyProblematicCode() })

これは、関数内ではなく、$ apply()が必要な場所です。そうしないと、コード全体に遅かれ早かれそのような区別が散らばってしまいます。このイベントハンドラーのコンテキストにスコープがあると仮定すると、次のように記述できます。

jQuery('.some-element').click(function() { 
    $scope.$apply(function() { seeminglyProblematicCode() })
})

ただし、注意が必要な注意事項が1つあります。コードからクリックイベントをトリガーすると、ダイジェストサイクルが既に進行しているという問題が発生します。これは、$ timeoutが必要な場所です。 この質問 への答えは、この問題を非常によくカバーしています。

4
lex82

私は同じ問題を抱えていましたが、私の修正は、ネストされたディレクティブでどのコントローラーが呼び出されているかを監視することでした。

# Parent Controller
app.controller 'storeController', ($scope, products) ->

  $scope.cart = ["chicken", "pizza"]
  $scope.addToCart = (item) ->
    $scope.cart.Push item

  # from service
  products.get().then (items) ->
    $scope.products = items

# Parent Directives
app.directive 'storeContainer', ($scope, config) ->
  restrict: 'E'
  templatUrl: 'store-container.html'
  controller: 'storeController'

# Nested Directive
app.directive 'storeFront', ($scope, config) ->
  restrict: 'E'
  templatUrl: 'store-front.html'
  controller: 'storeController'

# Parent Template templates/directives/store-container.html
<div ng-repeat="item in cart">{{ item }}</div>
<strore-front></store-front>

# Nested Template templates/directives/store-front.html
<ul ng-repeat="item in products">
  <li ng-click"addToCart(item)">{{ item }}</li>
</ul>

ここでのバグは、ネストされたディレクティブがプロトタイプチェーン内に2番目のコントローラー(storeControllerの複製)を作成し、親テンプレートがアクセスできないことです。解決するには、ネストされたコントローラーを次のように記述します。

# Nested Directive
app.directive 'storeFront', ($scope, config) ->
  restrict: 'E'
  templatUrl: 'store-front.html'

継承チェーンを作成するより良い方法がありますが、これにより、AngularJSを学習している多くの人々の問題が解決されます。

0
brettu