1
votes

I currently use

scope.onFocus = function(){ // change scope variables 
};

elem.bind('focus', function(){
   scope.$apply('onFocus()')});

to bind to the focus event in the link function of a directive.

The problem is if I fire the focus event manually like this: elem.focus() in say ng-click handler , I will get "apply is in progress" error.

Is the workaround to check whether apply has been called : if (! scope.$$phase) ?

Is it considered "Angularic" to check before calling apply?

Any other elegant solution?

UPDATED:

Here's my solution:

Since scope.onFocus can trigger external events (outside of Angular) which in turn can call $apply, you would have 'apply already in progress' error. The trick is to call $apply separately.

element.bind('focus', function(){
    scope.onFocus();
    scope.$apply(); // don't wrap onFocus call in $apply
})
2
Why would you do elem.focus() in ng-click? Why not onFocus()? - joakimbl

2 Answers

0
votes

You can use a directive to do this such as :

myapp.directive('onfocus', function() {
      return {
        restrict: 'A',
        scope: {
         onfocus:'=onfocus' 
            },
        link:function (scope, element, iAttrs, controller){
            element.bind('focus', function(event) {
                  scope.onfocus();
              });
        }

            };

    });

your view

<input type="text" onfocus="onFocus()" />

And your controller

scope.onFocus = function(){ // change scope variables 
};
0
votes

Honestly, if you are in a race condition, the best I can advice is you need to organize the code in a way that it should not occur, if it still stays, there is a problem with the code. $$phase is an internal implementation which Angular uses to check for current status of current digest cycle. Using $$phase is not future-safe and you should avoid using that.

The stack trace is very helpful for the race condition. It actually explains which other cycle is running at the moment in time which is producing the race.

There are complex situations like an extra API call which acts async and sycn at the same time (becomes sync cause of caching) in which you should try to handle it and make the API act in single manner.

Try to read in detail about $timeout/$interval, $apply/$digest and ngModel/ngModelController ($render / $setViewValue) . Also look closely into the third parameter passed to $timeout/$interval service. That might be very helpful in your current situation.