14

Other posts on this error always include someone trying to $apply without using a safe apply, but that's not the case in my example. My function IS successfully returning the data I requested from the API, but I can't clean this bug and it's driving me nuts. Every time before the .success is called in my $http function I get "Error: [$rootScope:inprog] $digest already in progress" in the console. Below are my controller and service. Thanks!

Here's my service including a function to post an $http call with a payload:

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;
}]);

And here's my controller which calls the 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);
}]);

The log below var new_cool_data gets called before the async operation, but new_cool does get assigned inside the .then statement within getCoolData. Any help getting rid of this bug or making it not crappy in general would be greatly appreciated!

Here's the whole error: https://gist.github.com/thedore17/bcac9aec781ef9ba535b

8
  • Do you have any more of the stack trace before the error? Commented Feb 18, 2014 at 16:01
  • This is the whole thing: gist.github.com/thedore17/bcac9aec781ef9ba535b Commented Feb 18, 2014 at 16:58
  • 1
    Your error is happening in ui-bootstrap, not your service: (anonymous function) ui-bootstrap-tpls-0.10.0.js:1539 Commented Feb 18, 2014 at 17:39
  • That explains a lot, thanks. Anything I can do about it? Technically everything is working, but I feel like it can't be good that I get that error. Commented Feb 18, 2014 at 20:41
  • Well, it's open source so you could always dig into the ui-bootstrap library. :) Or open an issue on their site. Commented Feb 18, 2014 at 20:47

4 Answers 4

9

Add this little method and call it inplace of apply()

function CheckScopeBeforeApply() {
    if(!$scope.$$phase) {
         $scope.$apply();
    }
};
Sign up to request clarification or add additional context in comments.

2 Comments

Yes, this is anti-pattern. See my answer below for an alternative.
I am getting the OP error too, however my trace just reports the error is coming from ionic.bundle.js Line 30758, char 9 in a function beginPhase(phase) {if ($rootScope.$$phase) { throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase) ; } $rootScope.$$phase = phase ; }. But its not telling me what triggered it. Through probably 20+ versions of my app over the last two years I have NEVER seen this error before, and its popped up twice when I submitted a new version of the app last night and it looks like either google or apples auto-review of my app triggered it.
1

There's an easier solution:

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

Or simply:

$scope.$evalAsync();

This avoids the problems caused by $scope.$apply(), though it should be noted that it won't run immediately (that's part of the reason you won't get the inprog error). I use this instead of $scope.$apply() and it has saved me from so much trouble.

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

Comments

0

This solve the issue for me. Just add it one time, it you don't need to change you code any more:

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;
    }
  ]);
})

Comments

0

I used alternate solution by putting $scope.$apply() in timeout like this and it worked...

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

I think it is just because, angular's apply lifecycle was already running and my manual $apply has interrupted it.

1 Comment

You can use the same for $digest() also.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.