Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Within a directive, why is it necessary to wrap .focus() in $timeout or $evalAsync in order to work?

Tags:

angularjs

In the code below, I cannot simply call "element[0].focus()" but instead need to wrap this in either $timeout or $evalAsync?

Full code and working example of the problem: http://plnkr.co/qW20iZ5D1tUpQ6gL6shZ?p=preview

app.setFocus = function ($timeout, $rootScope) {
  return {
    restrict: 'A',
    link: function (scope, element, attr) {
      scope.$watch(attr.setFocus, function (newValue, oldValue) {
        if (newValue === true && newValue != oldValue) {
          var performWork = function() {
            element[0].focus();
            console.log(document.activeElement);
          };

          // Question: Why do I need to execute performWork()
          // any of the two commented out ways below
          // in order for this to work? Why does not just
          // calling performWork() work?
          //$timeout(performWork, 0);
          //$rootScope.$evalAsync(performWork);

          performWork();
        }
      });
    }
  };
};
like image 405
eb80 Avatar asked Dec 06 '25 02:12

eb80


1 Answers

Give your directive a priority > 0

app.setFocus = function ($timeout, $rootScope) {
  return {
    restrict: 'A',
    priority: 1,

The problem happens because ngClass manipulates the DOM element after you set the focus, and probably it's responsible for losing the focus.

How to solve it?

  • You need ngClass $watch to run before your directive's $watch.
  • postLinking functions runs in reversed order ( low -> high priority )
  • $watches are invoked in the same order they are registered.
  • ngClass has no priority ( defaults to 0)

So by giving a priority > 0 to your directive you assure that ngClass $watch is registered before your directive's $watch

have fun!

like image 80
Ilan Frumer Avatar answered Dec 08 '25 14:12

Ilan Frumer