To set focus to an HTML form element, the focus() method of JavaScript can be used. To do so, call this method on an object of the element that is to be focused, as shown in the example. Example 1: The focus() method is set to the input tag when user clicks on Focus button.
The :focus selector is used to select the element that has focus. Tip: The :focus selector is allowed on elements that accept keyboard events or other user inputs.
Modify the show search method like this
showSearch(){
this.show = !this.show;
setTimeout(()=>{ // this will make the execution after the above boolean has changed
this.searchElement.nativeElement.focus();
},0);
}
You should use HTML autofocus for this:
<input *ngIf="show" #search type="text" autofocus />
Note: if your component is persisted and reused, it will only autofocus the first time the fragment is attached. This can be overcome by having a global DOM listener that checks for autofocus attribute inside a DOM fragment when it is attached and then reapplying it or focus via JavaScript.
Here is an example global listener, it only needs to be placed in your spa application once and autofocus will function regardless of how many times the same fragment is reused:
(new MutationObserver(function (mutations, observer) {
for (let i = 0; i < mutations.length; i++) {
const m = mutations[i];
if (m.type == 'childList') {
for (let k = 0; k < m.addedNodes.length; k++) {
const autofocuses = m.addedNodes[k].querySelectorAll("[autofocus]"); //Note: this ignores the fragment's root element
console.log(autofocuses);
if (autofocuses.length) {
const a = autofocuses[autofocuses.length - 1]; // focus last autofocus element
a.focus();
a.select();
}
}
}
}
})).observe(document.body, { attributes: false, childList: true, subtree: true });
This directive will instantly focus and select any text in the element as soon as it's displayed. This might require a setTimeout for some cases, it has not been tested much.
import { Directive, ElementRef, OnInit } from '@angular/core';
@Directive({
selector: '[appPrefixFocusAndSelect]',
})
export class FocusOnShowDirective implements OnInit {
constructor(private el: ElementRef) {
if (!el.nativeElement['focus']) {
throw new Error('Element does not accept focus.');
}
}
ngOnInit(): void {
const input: HTMLInputElement = this.el.nativeElement as HTMLInputElement;
input.focus();
input.select();
}
}
And in the HTML:
<mat-form-field>
<input matInput type="text" appPrefixFocusAndSelect [value]="'etc'">
</mat-form-field>
I'm going to weigh in on this (Angular 7 Solution)
input [appFocus]="focus"....
import {AfterViewInit, Directive, ElementRef, Input,} from '@angular/core';
@Directive({
selector: 'input[appFocus]',
})
export class FocusDirective implements AfterViewInit {
@Input('appFocus')
private focused: boolean = false;
constructor(public element: ElementRef<HTMLElement>) {
}
ngAfterViewInit(): void {
// ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
if (this.focused) {
setTimeout(() => this.element.nativeElement.focus(), 0);
}
}
}
This is working i Angular 8 without setTimeout:
import {AfterContentChecked, Directive, ElementRef} from '@angular/core';
@Directive({
selector: 'input[inputAutoFocus]'
})
export class InputFocusDirective implements AfterContentChecked {
constructor(private element: ElementRef<HTMLInputElement>) {}
ngAfterContentChecked(): void {
this.element.nativeElement.focus();
}
}
Explanation: Ok so this works because of: Change detection. It's the same reason that setTimout works, but when running a setTimeout in Angular it will bypass Zone.js and run all checks again, and it works because when the setTimeout is complete all changes are completed. With the correct lifecycle hook (AfterContentChecked) the same result can be be reached, but with the advantage that the extra cycle won't be run. The function will fire when all changes are checked and passed, and runs after the hooks AfterContentInit and DoCheck. If i'm wrong here please correct me.
More one lifecycles and change detection on https://angular.io/guide/lifecycle-hooks
UPDATE: I found an even better way to do this if one is using Angular Material CDK, the a11y-package. First import A11yModule in the the module declaring the component you have the input-field in. Then use cdkTrapFocus and cdkTrapFocusAutoCapture directives and use like this in html and set tabIndex on the input:
<div class="dropdown" cdkTrapFocus cdkTrapFocusAutoCapture>
<input type="text tabIndex="0">
</div>
We had some issues with our dropdowns regarding positioning and responsiveness and started using the OverlayModule from the cdk instead, and this method using A11yModule works flawlessly.
In Angular, within HTML itself, you can set focus to input on click of a button.
<button (click)="myInput.focus()">Click Me</button>
<input #myInput></input>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With