867 Stimmen

AngularJS : Verhinderung des Fehlers $digest already in progress beim Aufruf von $scope.$apply()

Ich finde, dass ich meine Seite zu meinem Bereich manuell mehr und mehr seit dem Aufbau einer Anwendung in Angular aktualisieren müssen.

Die einzige mir bekannte Möglichkeit, dies zu tun, ist der Aufruf $apply() aus dem Geltungsbereich meiner Kontrolleure und Weisungen. Das Problem dabei ist, dass es einen Fehler in der Konsole auslöst, der lautet :

Fehler: $digest bereits in Bearbeitung

Weiß jemand, wie man diesen Fehler vermeidet oder das Gleiche auf eine andere Weise erreicht?

3voto

RNobel Punkte 3233

Yearofmoo hat eine großartige Arbeit geleistet und eine wiederverwendbare $safeApply-Funktion für uns erstellt:

https://github.com/yearofmoo/AngularJS-Scope.SafeApply

Verwendung:

//use by itself
$scope.$safeApply();

//tell it which scope to update
$scope.$safeApply($scope);
$scope.$safeApply($anotherScope);

//pass in an update function that gets called when the digest is going on...
$scope.$safeApply(function() {

});

//pass in both a scope and a function
$scope.$safeApply($anotherScope,function() {

});

//call it on the rootScope
$rootScope.$safeApply();
$rootScope.$safeApply($rootScope);
$rootScope.$safeApply($scope);
$rootScope.$safeApply($scope, fn);
$rootScope.$safeApply(fn);

2voto

teleclimber Punkte 308

Ich konnte dieses Problem lösen, indem ich Folgendes aufrief $eval 代わりに $apply an Orten, von denen ich weiß, dass die $digest Funktion ausgeführt wird.

Nach Angaben der docs , $apply macht im Grunde Folgendes:

function $apply(expr) {
  try {
    return $eval(expr);
  } catch (e) {
    $exceptionHandler(e);
  } finally {
    $root.$digest();
  }
}

In meinem Fall ist ein ng-click ändert eine Variable innerhalb eines Bereichs, und ein $watch auf diese Variable ändert andere Variablen, die $applied . Dieser letzte Schritt führt zu der Fehlermeldung "digest already in progress".

Durch Ersetzen $apply mit $eval innerhalb des Watch-Ausdrucks werden die Bereichsvariablen wie erwartet aktualisiert.

Daher ist es erscheint dass, wenn Digest aufgrund einer anderen Änderung in Angular ohnehin ausgeführt wird, $eval Das ist alles, was Sie tun müssen.

2voto

Visakh B Sujathan Punkte 229

使用 $scope.$$phase || $scope.$apply(); stattdessen

1voto

ranbuch Punkte 1422

Dies ist mein Hilfsdienst:

angular.module('myApp', []).service('Utils', function Utils($timeout) {
    var Super = this;

    this.doWhenReady = function(scope, callback, args) {
        if(!scope.$$phase) {
            if (args instanceof Array)
                callback.apply(scope, Array.prototype.slice.call(args))
            else
                callback();
        }
        else {
            $timeout(function() {
                Super.doWhenReady(scope, callback, args);
            }, 250);
        }
    };
});

und dies ist ein Beispiel für seine Verwendung:

angular.module('myApp').controller('MyCtrl', function ($scope, Utils) {
    $scope.foo = function() {
        // some code here . . .
    };

    Utils.doWhenReady($scope, $scope.foo);

    $scope.fooWithParams = function(p1, p2) {
        // some code here . . .
    };

    Utils.doWhenReady($scope, $scope.fooWithParams, ['value1', 'value2']);
};

1voto

Ashu Punkte 569

Ich habe diese Methode angewandt und sie scheint perfekt zu funktionieren. Es wird einfach die Zeit abgewartet, bis der Zyklus beendet ist, und dann wird die apply() . Rufen Sie einfach die Funktion apply(<your scope>) von jedem Ort aus, den Sie wünschen.

function apply(scope) {
  if (!scope.$$phase && !scope.$root.$$phase) {
    scope.$apply();
    console.log("Scope Apply Done !!");
  } 
  else {
    console.log("Scheduling Apply after 200ms digest cycle already in progress");
    setTimeout(function() {
        apply(scope)
    }, 200);
  }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X