Получение ошибки AngularJS: [$ rootScope: inprog] $digest уже выполняется без ручного $apply

В других сообщениях об этой ошибке всегда упоминается, что кто-то пытается применить $apply без использования безопасного приложения, но в моем примере это не так. Моя функция успешно возвращает данные, которые я запросил у API, но я не могу исправить эту ошибку, и это сводит меня с ума. Каждый раз перед вызовом .success в моей функции $http я получаю сообщение «Ошибка: [$rootScope:inprog] $digest уже выполняется» в консоли. Ниже мой контроллер и сервис. Спасибо!

Вот мой сервис, включающий функцию отправки вызова $http с полезной нагрузкой:

Services.service( 'CoolService', ['$q', '$rootScope', '$http', 'Auth', function($q, $rootScope, $http, Auth){
var service = {
    create: function(payload){
        var deferred = $q.defer();
        $http({
            'url': '/api/endpoint/',
            'dataType':'json',
            'method': 'POST',
            data: payload
        }).success(function(data,status, headers, config){
            deferred.resolve(data);

        })
        .error(function(data, status, headers, config){
            deferred.reject("Error in request.");
        });
        return deferred.promise;
        }
    }
    return service;
}]);

А вот мой контроллер, который вызывает службу:

controllers.controller('CoolCtrl',['$scope', '$modal', '$log','CoolService', function($scope, $modal, $log, CoolService){
    getCoolData = function (input_data) {
        CoolService.create(input_data).then(function(results){
            new_cool = results.results;
        }, function(error){
        console.log("there was an error getting new cool data");
        });
    };
    var payload = {
        user_id: data1,
        cool_id: data2,
    }
    var new_cool_data = getCoolData(payload);
    console.log(new_cool_data);
}]);

Журнал ниже var new_cool_data вызывается перед асинхронной операцией, но new_cool назначается внутри оператора .then в getCoolData. Мы будем очень признательны за любую помощь в избавлении от этой ошибки или в том, чтобы сделать ее не дрянной в целом!

Вот и вся ошибка: https://gist.github.com/thedore17/bcac9aec781ef9ba535b


person TedCap    schedule 18.02.2014    source источник
comment
У вас есть еще трассировка стека до ошибки?   -  person Geoff Genz    schedule 18.02.2014
comment
Вот и все: gist.github.com/thedore17/bcac9aec781ef9ba535b   -  person TedCap    schedule 18.02.2014
comment
Ваша ошибка происходит в ui-bootstrap, а не в вашем сервисе: (анонимная функция) ui-bootstrap-tpls-0.10.0.js:1539   -  person Geoff Genz    schedule 18.02.2014
comment
Это многое объясняет, спасибо. Я могу что-нибудь с этим сделать? Технически все работает, но я чувствую, что не может быть хорошо, что я получаю эту ошибку.   -  person TedCap    schedule 19.02.2014
comment
Что ж, это открытый исходный код, поэтому вы всегда можете покопаться в библиотеке ui-bootstrap. :) Или открыть вопрос на их сайте.   -  person Geoff Genz    schedule 19.02.2014
comment
не будет ли new_cool_data всегда неопределенным? Какой смысл его печатать. И да, ошибка в ui-bootstrap. Мы можем отладить его, если вы сможете воспроизвести его в plunkr.   -  person Abhik    schedule 06.04.2014
comment
Может быть ошибка в ui-bootstrap: github.com/angular-ui/bootstrap/issues /1798 Не могли бы вы попробовать 0.11.x ui-bootstrap?   -  person aet    schedule 06.05.2014
comment
Просто чтобы вмешаться: у меня была похожая ошибка, указывающая на то, что виноват пользовательский интерфейс начальной загрузки, но в итоге это была другая директива, которая агрессивно отслеживала ширину контейнера html и без необходимости вызывала scope.$apply(). Используете ли вы какие-либо другие директивы/модули?   -  person Cory Silva    schedule 16.05.2014


Ответы (4)


Добавьте этот маленький метод и назовите его вместо apply()

function CheckScopeBeforeApply() {
    if(!$scope.$$phase) {
         $scope.$apply();
    }
};
person HandyManDan    schedule 19.05.2014
comment
Да, это антипаттерн. Смотрите мой ответ ниже для альтернативы. - person Sam; 24.05.2017

Это решает проблему для меня. Просто добавьте его один раз, вам больше не нужно менять код:

https://github.com/angular/angular.js/issues/10083#issuecomment-145967719

.config(function($provide) {
  // Workaround for https://github.com/angular/angular.js/issues/10083
  $provide.decorator('$rootScope', ['$delegate', '$exceptionHandler',
    function($delegate, $exceptionHandler) {
      var proto = Object.getPrototypeOf($delegate);
      var originalDigest = proto.$digest, originalApply = proto.$apply;
      proto.$digest = function() {
        if ($delegate.$$phase === '$digest' || $delegate.$$phase === '$apply') return;
        originalDigest.call(this);
      };
      proto.$apply = function(fn) {
        if ($delegate.$$phase === '$digest' || $delegate.$$phase === '$apply') {
          try {
            this.$eval(fn);
          } catch(e) {
            $exceptionHandler(e);
          }
        } else {
          originalApply.call(this, fn);
        }
      };
      return $delegate;
    }
  ]);
})
person Aminadav Glickshtein    schedule 18.11.2015

Я использовал альтернативное решение, поместив $scope.$apply() в такой тайм-аут, и это сработало...

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

Я думаю, это просто потому, что жизненный цикл приложения angular уже запущен, и мой ручной $apply прервал его.

person Sahil Kanani    schedule 12.02.2016
comment
Вы также можете использовать то же самое для $digest(). - person Sahil Kanani; 12.02.2016

Есть более простое решение:

$scope.$evalAsync(function() {
    // Code here
});

Или просто:

$scope.$evalAsync();

Это позволяет избежать проблем, вызванных $scope.$apply(), хотя следует отметить, что он не запустится немедленно (это одна из причин, по которой вы не получите ошибку inprog). Я использую это вместо $scope.$apply(), и это избавило меня от многих проблем.

См.: https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$evalAsync

person Sam    schedule 23.05.2017