Unfortunately, using .querySelector('[formcontrolName="' + key + '"]') is not recommended.
Instead, it is suggested to utilize a directive to focus on the invalid field.
@Directive({
selector: '[focusOnError]'
})
export class FocusOnErrorDirective {
@ContentChildren(NgControl, { descendants: true }) fields: QueryList<NgControl>
@HostListener('submit')
check() {
const fields = this.fields.toArray();
// By logging field, we can determine how to access the nativeElement
for (let field of fields) {
if (field.invalid) {
const nativeElement = field.valueAccessor && (field.valueAccessor as any)._elementRef ?
(field.valueAccessor as any)._elementRef.nativeElement : null;
if (nativeElement) {
nativeElement.focus();
}
break;
}
}
}
}
To implement the directive in your <form>
, simply add it like so:
<form [formGroup]="form" focusOnError (submit)="submit(form)">
...
</form>
An example can be found on this stackblitz link
Note: If dealing with complex elements like custom formControls or ng-autocomplete from angular-ng-autocomplete, accessing the nativeElement might require additional steps.
For instance, with angular-ng-autocomplete, you can access the nativeElement using
(field.valueAccessor as any).searchInput.nativeElement
By examining the field object in the console, you can improve the directive accordingly.
check() {
const fields = this.fields.toArray();
for (let field of fields) {
if (field.invalid) {
const nativeElement =field.valueAccessor?
(field.valueAccessor as any)._elementRef?
(field.valueAccessor as any)._elementRef.nativeElement
: (field.valueAccessor as any).searchInput?
(field.valueAccessor as any).searchInput.nativeElement
: null:
null;
if (nativeElement) {
nativeElement.focus();
}
break;
}
}
}
Make sure to check for field.valueAccessor and proceed accordingly to reach the desired nativeElement.