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?

33voto

Ciul Punkte 635

Ich hatte das gleiche Problem mit Skripten von Drittanbietern wie z.B. CodeMirror und Krpano, und auch die hier erwähnten safeApply-Methoden haben den Fehler bei mir nicht behoben.

Aber was hat es gelöst ist mit $timeout Dienst (vergessen Sie nicht, es zuerst zu injizieren).

Also etwa so:

$timeout(function() {
  // run my code safely here
})

und wenn Sie in Ihrem Code Folgendes verwenden

diese

vielleicht, weil es sich innerhalb des Controllers einer Fabrikrichtlinie befindet oder einfach nur eine Art von Bindung benötigt, dann würden Sie etwas tun wie:

.factory('myClass', [
  '$timeout',
  function($timeout) {

    var myClass = function() {};

    myClass.prototype.surprise = function() {
      // Do something suprising! :D
    };

    myClass.prototype.beAmazing = function() {
      // Here 'this' referes to the current instance of myClass

      $timeout(angular.bind(this, function() {
          // Run my code safely here and this is not undefined but
          // the same as outside of this anonymous function
          this.surprise();
       }));
    }

    return new myClass();

  }]
)

32voto

Trevor Punkte 12546

Voir http://docs.angularjs.org/error/$rootScope:inprog

Das Problem tritt auf, wenn Sie einen Aufruf an $apply die manchmal asynchron außerhalb von Angular-Code ausgeführt wird (wenn $apply verwendet werden sollte) und manchmal synchron innerhalb von Angular-Code (was dazu führt, dass die $digest already in progress Fehler).

Dies kann z. B. passieren, wenn Sie eine Bibliothek haben, die asynchron Elemente von einem Server abruft und in den Cache stellt. Beim ersten Mal, wenn ein Element angefordert wird, wird es asynchron abgerufen, um die Codeausführung nicht zu blockieren. Beim zweiten Mal jedoch befindet sich das Element bereits im Cache, so dass es synchron abgerufen werden kann.

Um diesen Fehler zu vermeiden, muss sichergestellt werden, dass der Code, der die $apply wird asynchron ausgeführt. Dies kann erreicht werden, indem Sie Ihren Code innerhalb eines Aufrufs von $timeout mit einer Verzögerung von 0 (dies ist die Standardeinstellung). Wenn Sie jedoch Ihren Code innerhalb von $timeout entfällt die Notwendigkeit des Aufrufs $apply denn $timeout löst eine weitere $digest Zyklus, der seinerseits alle notwendigen Aktualisierungen vornimmt usw.

Lösung

Kurz gesagt, anstatt dies zu tun:

... your controller code...

$http.get('some/url', function(data){
    $scope.$apply(function(){
        $scope.mydate = data.mydata;
    });
});

... more of your controller code...

dies tun:

... your controller code...

$http.get('some/url', function(data){
    $timeout(function(){
        $scope.mydate = data.mydata;
    });
});

... more of your controller code...

Nur anrufen $apply wenn Sie wissen, dass der Code, der ihn ausführt, immer außerhalb des Angular-Codes ausgeführt wird (z.B. wird Ihr Aufruf von $apply innerhalb eines Callbacks erfolgen, der von Code außerhalb Ihres Angular-Codes aufgerufen wird).

Es sei denn, jemand ist sich eines erheblichen Nachteils bei der Verwendung von $timeout über $apply Ich wüsste nicht, warum man nicht immer die Option $timeout (mit Nullverzögerung) anstelle von $apply da es in etwa das Gleiche bewirkt.

29voto

dnc253 Punkte 39427

Wenn Sie diese Fehlermeldung erhalten, bedeutet dies im Grunde, dass die Ansicht bereits aktualisiert wird. Sie sollten wirklich nicht brauchen, um $apply() innerhalb Ihres Controllers. Wenn Ihre Ansicht nicht so aktualisiert wird, wie Sie es erwarten würden, und Sie diesen Fehler nach dem Aufruf von $apply() dann bedeutet das höchstwahrscheinlich, dass Sie das Modell nicht richtig aktualisieren. Wenn Sie einige Einzelheiten angeben, können wir das Kernproblem herausfinden.

14voto

Warlock Punkte 7083

Die kürzeste Form von safe $apply ist:

$timeout(angular.noop)

11voto

CMCDragonkai Punkte 5795

Sie können auch evalAsync verwenden. Es wird irgendwann nach Abschluss von digest ausgeführt!

scope.evalAsync(function(scope){
    //use the scope...
});

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