Reputation: 375
I have a significantly large form and the way the application is laid out, the form is in a scrolling div, so I can't use (because it doesn't seem to work) something like:
private scrollToFirstInvalidControl() {
const firstInvalidControl: HTMLElement = this.el.nativeElement.querySelector(
"form .ng-invalid"
);
firstInvalidControl.focus();
}
This is a one-off thing, I also don't want it as a directive, it's just overkill, I just want to focus on the first invalid object in the formGroup after I run this.form.markAllAsTouched(); and walk away.. smooth scrolling would be a nice bonus, but not a huge deal.
Upvotes: 2
Views: 6268
Reputation: 61
I have created a directive for this, it's easier and reusable:
@Directive({
selector: '[scrollToFirsInvalidFormField]',
standalone: true,
})
export class ScrollToFirstInvalidFormFieldDirective {
private readonly elementRef = inject(ElementRef);
@HostListener('ngSubmit')
onSubmit(): void {
this.scrollToFirstInvalidField();
}
private scrollToFirstInvalidField(): void {
const invalidFields =
this.elementRef.nativeElement.querySelectorAll('.ng-invalid');
const firstInvalidField = invalidFields[0];
if (!firstInvalidField) {
return;
}
firstInvalidField.scrollIntoView({
behavior: 'smooth',
block: 'center',
});
firstInvalidField.classList.add('ng-dirty');
}
}
On the form you need to add following:
<form [formGroup]="formService.form" (ngSubmit)="submit()">
<button type="submit" />
</form>
Upvotes: 0
Reputation: 8330
You can also use the ElementRef
and scrollIntoView
for navigating close to invalid element:
private scrollToFirstInvalidControl(): void {
const formElement = elementRef.nativeElement.querySelector('.form'); // get the form by class name
if (formElement) {
const firstErrorElement = formElement.querySelector('.ng-invalid'); // get the first error with ng invlalid input class name
if (firstErrorElement) {
firstErrorElement.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' }); // you can also use block: 'start' for closer navigation
}
}
}
Upvotes: 0
Reputation: 2113
You can try like this (change formId
to actual id of your form:
private scrollToFirstInvalidControl() {
let form = document.getElementById('formId'); // <-- your formID
let firstInvalidControl = form.getElementsByClassName('ng-invalid')[0];
firstInvalidControl.scrollIntoView();
(firstInvalidControl as HTMLElement).focus();
}
Upvotes: 6