What is $$phase in AngularJS?


I found this code snippet which is part of a angular directive someone wrote for bootstrap modal.

//Update the visible value when the dialog is closed                                                                                                                                                                                                            
                //through UI actions (Ok, cancel, etc.)                                                                                                                                                                                                                         
                element.bind("hide.bs.modal", function () {                                                                                                                                                                                                                     
                    scope.modalVisible = false;                                                                                                                                                                                                                                 
                    if (!scope.$$phase && !scope.$root.$$phase)                                                                                                                                                                                                                 

I understood that this part is for the latter half of two way binding we bind to hide.bs.modal event and update modal when UI changes.

I just wanted to know why is the person checking $$phase for scope and rootScope before calling apply ?

Can't we straightaway call apply ?

What is $$phase here?

I tried searching a lot, couldn't find any good explanation.


I found where I saw the example: Simple Angular Directive for Bootstrap Modal

Problem courtesy of: Amogh Talpallikar


$$phase is a flag set while angular is in a $digest cycle.

Sometimes (in rare cases), you want to check $$phase on the scope before doing an $apply. An error occurs if you try to $apply during a $digest:

Error: $apply already in progress

Solution courtesy of: Davin Tryon


In that example, the element binding will get executed from a non-angular event. In most cases, it is safe to just call $apply() without checking the phase.

If you look at the rest of the code, however, there is a $scope function called showModal(). This function calls into the non-angular code which will likely cause a "hide.bs.modal" event to fire. If the event fires via this route, then the call stack is within a $digest.

So, this event does fall within the rare case of a function that will get called from both angular-managed code AND non-angular code. Checking the $$phase in this case is necessary because you don't know how the event originated. If the $$phase is set to something, then the digest loop will finish to completion and $apply() doesn't need to be called.

This pattern is often referred to as "safe apply".

Discussion courtesy of: Brian Genisio

Davin is totally correct that it's a flag that angular sets during the digest cycle.

But don't use it in your code.

I recently got a chance to ask Misko (angular author) about $$phase, and he said to never use it; it's an internal implementation of the digest cycle, and it's not future safe.

To make sure your code continues to work in the future, he suggested wrapping whatever you want to "safe apply" inside of a $timeout

$timeout(function() {
  // anything you want can go here and will safely be run on the next digest.

This comes up a lot when you have callbacks or other things that might resolve during the digest cycle (but don't always)

Here's an example snippet from when I was dealing with one of google's libraries: (The rest of the service this was from has been left off.)

window.gapi.client.load('oauth2', 'v2', function() {
    var request = window.gapi.client.oauth2.userinfo.get();
    request.execute(function(response) {
        // This happens outside of angular land, so wrap it in a timeout 
        // with an implied apply and blammo, we're in action.
        $timeout(function() {
            if(typeof(response['error']) !== 'undefined'){
                // If the google api sent us an error, reject the promise.
                // Resolve the promise with the whole response if ok.

Note that the delay argument for $timeout is optional and will default to 0 if left unset ($timeout calls $browser.defer which defaults to 0 if delay isn't set)

A little non-intuitive, but that's the answer from the guys writing Angular, so it's good enough for me!

Discussion courtesy of: betaorbust

my understanding is it is good to use when digesting or applying the scope. If it is truthy it means that there is currently a $digest or $apply phase in progress. If you are getting related errors you can do $scope.$$phase || $scope.digest(); which will only digest if $scope.$$pahse is falsy.

Discussion courtesy of: majo

This recipe can be found in it's original form on Stack Over Flow.