web-dev-qa-db-ja.com

$ applyはすでに進行中のエラーです

スタックトレース:

Error: $apply already in progress
at Error (<anonymous>)
at beginPhase (file:///Android_asset/www/built.min.js:7:22740)
at Object.Scope.$apply (file:///Android_asset/www/built.min.js:7:25967)
at navigator.geolocation.getCurrentPosition.that (file:///Android_asset/www/built.min.js:13:8670)
at Object.geolocation.getCurrentPosition (file:///Android_asset/www/plugins/org.Apache.cordova.core.geolocation/www/geolocation.js:122:13)
at Object.getCurrentPosition (file:///Android_asset/www/built.min.js:13:8589)
at Object.getCurrentPosition (file:///Android_asset/www/built.min.js:13:8277)
at Object.getCurrentCity (file:///Android_asset/www/built.min.js:13:8941)
at Object.$scope.locateDevice (file:///Android_asset/www/built.min.js:13:10480)
at file:///Android_asset/www/built.min.js:7:12292:7

このコードを参照します http://Pastebin.com/B9V6yvF

    getCurrentPosition: cordovaReady(function (onSuccess, onError, options) {

        navigator.geolocation.getCurrentPosition(function () {
            var that = this,
                args = arguments;

            if (onSuccess) {
                $rootScope.$apply(function () {
                    onSuccess.apply(that, args);
                });
            }
        }, function () {
            var that = this,
                args = arguments;
            if (onError) {
                $rootScope.$apply(function () {
                    onError.apply(that, args);
                });
            }
        }, {
            enableHighAccuracy: true,
            timeout: 20000,
            maximumAge: 18000000
        });
    })

奇妙なことに、私のLG4Xではうまく動きますが、私のサムスンS2ではそれは上記のエラーをスローします。何か考えが間違っていますか?

128
Artjom Zabelin

既存の消化サイクル内で$applyを呼び出しているため、このエラーが発生しています。

大きな問題は、なぜあなたは$applyを呼び出しているのですか? Angular以外のイベントからインタフェースしているのでなければ、$applyを呼び出す必要はありません。 $applyの存在は通常私が何か悪いことをしていることを意味します(再度、$ applyが非Angularイベントから発生しない限り).

ここで$applyが本当に適切な場合は、 "安全な適用"アプローチの使用を検討してください。

https://coderwall.com/p/ngisma

102
Brian Genisio

$applyの代わりに $ evalAsync を使うだけです。

56
Adrian Neatu

あなたはこのステートメントを使用することができます:

if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') {
    $scope.$apply();
}
38
Dariraze

スコープを適用する必要がある場合は、$ applyが次のティックまで延期されるようにタイムアウトを設定できます。

setTimeout(function(){ scope.$apply(); });

または$ timeout(function(){..})でコードをラップしてください。実行終了時にスコープが自動的に適用されるためです。あなたがあなたの機能が同期的に振る舞うことを必要とするならば、私は最初にするでしょう。

22
jeff.d

Angular 1.3では、$scope.$applyAsync()という新しい関数が追加されたと思います。この関数呼び出しは後で適用されます - 彼らは少なくとも10ミリ秒後に言っています。それは完璧ではありませんが、それは少なくとも迷惑なエラーを排除します。

https://docs.angularjs.org/api/ng/type/ $ rootScope.Scope#$ applyAsync

9
user3413723

私の場合、私はいくつかのイベントをリンクするために角度カレンダーUIで$applyを使用します。

$scope.eventClick = function(event){           
    $scope.$apply( function() {
        $location.path('/event/' + event.id);
    });
};

問題のドキュメントを読んだ後: https://docs.angularjs.org/error/ $ rootScope/inprog

部分矛盾API(同期/非同期)は非常に興味深いものです。

たとえば、私たちのためにデータを取得するメソッドを持つサードパーティのライブラリを想像してください。サーバーに対して非同期呼び出しを行っている可能性があるので、データが到着したときに呼び出されるコールバック関数を受け入れます。

MyControllerコンストラクターは常に$ apply呼び出し内からインスタンス化されるため、ハンドラーは新しい$ applyブロックをその中から入力しようとしています。

コードを次のように変更します。

$scope.eventClick = function(event){           
    $timeout(function() {
        $location.path('/event/' + event.id);
    }, 0);
};

魅力のように動作します!

ここでは将来のコールスタックでスコープへの変更をスケジュールするために$ timeoutを使いました。 0msのタイムアウト期間を提供することによって、これはできるだけ早く起こり、$ timeoutはコードが単一の$ applyブロックで呼び出されることを保証します。

8
mpgn

どの時点でも、進行中の$digestまたは$apply操作は1つだけです。これは、検出しにくいバグがアプリケーションに侵入するのを防ぐためです。このエラーのスタックトレースを使用すると、エラーの原因となっている現在実行中の$applyまたは$digest呼び出しの発生元をトレースできます。

詳細情報: https://docs.angularjs.org/error/$rootScope/inprog?p0=$apply

3
forgottofly

この問題を解決しました。その文書化された ここ

同じフロー内で$rootScope.$applyを2回呼び出していました。私がしたことは、サービス関数の内容をsetTimeout(func, 1)でラップしただけです。

2
user405398

私はそれが古い質問であることを知っています、しかしあなたが本当に$ scopeを使う必要があるならば。

1
akaco

私は$ scopeを呼びます。$はこのように複数回無視された呼び出しに一度に適用されます。

      var callApplyTimeout = null;
      function callApply(callback) {
          if (!callback) callback = function () { };
          if (callApplyTimeout) $timeout.cancel(callApplyTimeout);

          callApplyTimeout = $timeout(function () {
              callback();
              $scope.$apply();
              var d = new Date();
              var m = d.getMilliseconds();
              console.log('$scope.$apply(); call ' + d.toString() + ' ' + m);
          }, 300);
      }

単に電話する

callApply();
0
Marosdee Uma