What is the 'Angular way' to set focus on input field in AngularJS?
More specific requirements:
- When a Modal is opened, set focus on a predefined
<input>
inside this Modal. - Everytime
<input>
becomes visible (e.g. by clicking some button), set focus on it.
I tried to achieve the first requirement with autofocus
, but this works only when the Modal is opened for the first time, and only in certain browsers (e.g. in Firefox it doesn't work).
Any help will be appreciated.
Here is my original solution:
plunker
And the HTML:
What it does:
It focuses the input as it becomes visible with ng-show. No use of $watch or $on here.
Not to resurrect a zombie or plug my own directive (ok that's exactly what I'm doing):
https://github.com/hiebj/ng-focus-if
http://plnkr.co/edit/MJS3zRk079Mu72o5A9l6?p=preview
Mark and Blesh have great answers; however, Mark's has a flaw that Blesh points out (besides being complex to implement), and I feel that Blesh's answer has a semantic error in creating a service that's specifically about sending focus request to the frontend when really all he needed was a way to delay the event until all the directives were listening.
So here is what I ended up doing which steals a lot from Blesh's answer but keeps the semantics of the controller event and the "after load" service separate.
This allows the controller event to easily be hooked for things other than just focusing a specific element and also allows to incur the overhead of the "after load" functionality only if it is needed, which it may not be in many cases.
Usage
Source
If you just wanted a simple focus that was controlled by an ng-click.
Html:
Directive:
I edit Mark Rajcok's focusMe directive to work for multiple focus in one element.
HTML:
in AngularJs Controller:
AngulaJS Directive:
Define a directive and have it $watch a property/trigger so it knows when to focus the element:
Plunker
The $timeout seems to be needed to give the modal time to render.
Create a directive essentially like the one above. Watch some scope property, and when it becomes true (set it in your ng-click handler), execute
element[0].focus()
. Depending on your use case, you may or may not need a $timeout for this one:Plunker
Update 7/2013: I've seen a few people use my original isolate scope directives and then have problems with embedded input fields (i.e., an input field in the modal). A directive with no new scope (or possibly a new child scope) should alleviate some of the pain. So above I updated the answer to not use isolate scopes. Below is the original answer:
Original answer for 1., using an isolate scope:
Plunker.
Original answer for 2., using an isolate scope:
Plunker.
Since we need to reset the trigger/focusInput property in the directive, '=' is used for two-way databinding. In the first directive, '@' was sufficient. Also note that when using '@' we compare the trigger value to "true" since @ always results in a string.