Для управления входами формы, я думаю, лучшее решение - использовать ViewChildren для получения всех элементов. Таким образом, мы можем зациклить эти элементы и сосредоточить внимание на первом.
Итак, мы можем иметь более простую директиву:
@Directive({
selector: '[focusOnError]'
})
export class FocusOnErrorDirective {
public get invalid()
{
return this.control?this.control.invalid:false;
}
public focus()
{
this.el.nativeElement.focus()
}
constructor(@Optional() private control: NgControl, private el: ElementRef) { }
}
И, в нашем компоненте у нас есть что-то вроде
@ViewChildren(FocusOnErrorDirective) fields:QueryList<FocusOnErrorDirective>
check() {
const fields=this.fields.toArray();
for (let field of fields)
{
if (field.invalid)
{
field.focus();
break;
}
}
}
Вы можете увидеть в действии * * * * * * * * * * * * * * * 1011 *
ОБНОВЛЕНИЕ всегда можно улучшить:
Почему бы не создать директиву, которая применяется к форме?
@Directive({
selector: '[focusOnError]'
})
export class FocusOnErrorDirective {
@ContentChildren(NgControl) fields: QueryList<NgControl>
@HostListener('submit')
check() {
const fields = this.fields.toArray();
for (let field of fields) {
if (field.invalid) {
(field.valueAccessor as any)._elementRef.nativeElement.focus();
break;
}
}
}
Итак, наш .html это как
<form [formGroup]="myForm" focusOnError>
<input type="text" formControlName="familyName" />
<input type="text" formControlName="appointmentCode" />
<button >click</button>
</form>
См. stackblitz
Еще больше, если использовать в качестве селектора форму
@Directive({
selector: 'form'
})
Даже мы можем убрать focusOnError в виде
<form [formGroup]="myForm" (submit)="submit(myForm)">
..
</form>
Обновление 2 Проблемы с formGroup с formGroup.
NgControl учитывает только те элементы управления, которые имеют [(ngModel)], formControlName и [formControl], поэтому. Если мы можем использовать форму как
myForm = new FormGroup({
familyName: new FormControl('', Validators.required),
appointmentCode: new FormControl('', Validators.required),
group: new FormGroup({
subfamilyName: new FormControl('', Validators.required),
subappointmentCode: new FormControl('', Validators.required)
})
})
Мы можем использовать форму как:
<form [formGroup]="myForm" focusOnError (submit)="submit(myForm)">
<input type="text" formControlName="familyName" />
<input type="text" formControlName="appointmentCode" />
<div >
<input type="text" [formControl]="group.get('subfamilyName')" />
<input type="text" [formControl]="group.get('subappointmentCode')" />
</div>
<button >click</button>
</form>
где в .ts у нас есть
get group()
{
return this.myForm.get('group')
}