Dave
Dave

Reputation: 1051

Angularjs focus unexpectedly requires an async setTimeout to work

Ok StackOverflow, riddle me this.

I have a button that I click on which toggles the visibility of an input. In the scope function which changes the visibility I use javascript to set focus on that input tag. What I want to know is why does it not work unless I wrap it in a setTimeout?

$scope.toggle = function() {
  if ($scope.hideInput) {
    setTimout(function(){
      input.focus();
    }, 0);  // That's right, zero!
  }
  $scope.hideInput = !scope.hideInput;
};

Here's a working jsfiddle with a button that correctly sets the focus and a button that doesn't:

http://jsfiddle.net/PsS99/1/

Upvotes: 1

Views: 287

Answers (1)

Konstantin Krass
Konstantin Krass

Reputation: 8646

Can tell you the reason why.

First you can't focus element, with css display:none.

So in the one (broken) method, you focus the element before it is actually displayed. Because the angular will go line to line and $scope.hideInput = !scope.hideInput; will trigger the watcher for a digest-loop. In that loop your input will be set to display: block.

The timeout will move the focus command into it's own thread, and the $scope.hideInput = !scope.hideInput; will trigger the digest, too. But the digest is curiously fast enought to display the element before the input.focus(); will be executed.

This is my explanation but understanding this, did help me in some curious problems of angular's timing.

Maybe use this ? http://ngmodules.org/modules/ng-focus-on

A directive to set the focus by variable.

Upvotes: 1

Related Questions