3

I'm trying to focus an input box with AngularJS. To achieve that I created a custom directive, but for some reasons it doesn't work on a particular input box.

This is my 'focus' directive:

angular.module('app.ui.input').directive('ooFocus', function()
{
    return {
        scope : {
            trigger : '=ooFocus'
        },
        restrict : 'A',
        link : function(scope, element, attrs)
        {
            scope.$watch('trigger', function(value)
            {
                if(value)
                {
                    console.log('this will be printed');
                    element[0].focus();
                    element[0].select();
                }
            });
        }
    }
});

And this is how it looks like when it's being applied to the input box:

<input placeholder="Company name" type="text" ng-model="company.name" ng-blur="hide()" oo-focus="show" required>

The form containing the input box is hidden and it's displayed when show is set to true. show is passed to the oo-focus directive and I can see that the directive is printing this will be printed in the console whenever show is set to true, but for some reasons the input is not focused.

2 Answers 2

3

You can't focus what's hidden, it's as simple as that. So you have to be sure that your input is displayed before trying to focus it.

The problem is that usually you are not working with css directly, which would show the element immediately. Usually you are using a directive like ng-show or ng-if and you can't even be sure if they are evaluated before ooFocus.

Using $timeout to delay the focus is a good solution for such a situation.

Sign up to request clarification or add additional context in comments.

3 Comments

This is a really good explanation, thank you :) Could it be that if I have a slow computer I need to set a longer timeout?
@siannone That shouldn't matter, usually you are using zero timeout which only means "handle this when everything else has been handled". Then you can be sure that the element has been displayed and you can focus it.
I have the same issue except I'm not in $watch use case. Using $timeout ,no matter how long it is, doesn't help. Odd thing though: it works perfectly when I add a breakpoint through sources devtool.
1

I have one work around for this. Try using $timeout inside directive like this,

.directive('ooFocus',function($timeout) {
return {
    scope : {
        trigger : '=ooFocus'
    },
    restrict : 'A',
    link : function(scope, element) {

        scope.$watch('trigger', function(value) {
          if (value) {
            $timeout(function() {
                element[0].focus();
            });
          }
        });
    }
};

});

2 Comments

I did that exactly 30 seconds before reading your answer and this works. The question is: Why? P.S. value === "true" should be fixed in your answer because i'm comparing value with the boolean value true not with the string "true".
I told you it as a work around but $timeout gives some time for the element to render before trying to focus it !!!

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.