Angular 自定义焦点指令.聚焦表单的第一个无效输入 [英] Angular Custom focus Directive. Focus a form's first invalid input

查看:50
本文介绍了Angular 自定义焦点指令.聚焦表单的第一个无效输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个指令来聚焦无效的输入

I have created a directive to focus an input if it's invalid

import { Directive, Input, Renderer2, ElementRef, OnChanges } from '@angular/core';

@Directive({
  // tslint:disable-next-line:directive-selector
  selector: '[focusOnError]'
})
export class HighlightDirective implements OnChanges {
  @Input() submitted: string;

  constructor(private renderer: Renderer2, private el: ElementRef) { }

  ngOnChanges(): void {
    const el = this.renderer.selectRootElement(this.el.nativeElement);
    if (this.submitted && el && el.classList.contains('ng-invalid') && el.focus) {
      setTimeout(() => el.focus());
    }
  }

}

我确实有一个带有两个输入的反应式形式,并且我已将指令应用于两个输入

I do have a reactive form with two inputs, and I've applied the directive to both inputs

<form>
  ...
  <input type="text" id="familyName" focusOnError />
  ...
  <input type="text" id="appointmentCode" focusOnError />
  ...
</form>

提交表单后它工作正常,但我正在努力实现以下目标:

After submitting the form it works fine, but what I'm struggling to achieve is the following:

预期结果:- 如果两个输入都无效,提交表单后,只应关注第一个.

Expected result: - After submitting the form if both inputs are invalid, only the first one should be focused.

当前结果:- 如果两个输入都无效,提交表单后,第二个将获得焦点.

Current result: - After submitting the form if both inputs are invalid, the second one gets focused.

我不知道如何指定仅当它是第一个孩子时才这样做",我尝试过使用指令的选择器但没有成功.

I don't know how to specify "only do this if it's the first child", I've tried with the directive's selector with no luck.

有什么想法吗?

非常感谢.

推荐答案

为了控制 Form 的输入,我认为更好的解决方案是使用 ViewChildren 来获取所有元素.因此,我们可以循环遍历这些元素并聚焦第一个.

To control the inputs of a Form, I think the better solution is use ViewChildren to get all elements. So, we can loop over this elements and focus the first.

所以,我们可以有一个辅助的简单指令:

So, we can has a auxiliar simple directive :

@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) {  }
}

而且,在我们的组件中,我们有一些类似

And, in our component we has some like

@ViewChildren(FocusOnErrorDirective) fields:QueryList<FocusOnErrorDirective>
check() {
    const fields=this.fields.toArray();
    for (let field of fields)
    {
      if (field.invalid)
      {
        field.focus();
        break;
      }
    }
  }

您可以在 stackblitz

更新总是可以改进的:

为什么不创建一个应用于表单的指令?

Why not create a directive that applied to the form?

@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 就像

So, our .html it's like

<form [formGroup]="myForm" focusOnError>
  <input type="text" formControlName="familyName" />
  <input type="text" formControlName="appointmentCode" />
  <button >click</button>
</form>

请参阅stackblitz

甚至更多,如果我们使用作为选择器形式

See the stackblitz

Even more, if we use as selector form

甚至我们可以删除表单中的 focusOnError

@Directive({ selector: 'form' })

Even we can remove the focusOnError in the form

更新 2 formGroup 与 formGroup 的问题.已解决

<form [formGroup]="myForm" (submit)="submit(myForm)"> .. </form>

NgControl 只考虑具有 [(ngModel)]、formControlName 和 [formControl] 的控件,所以.如果我们可以使用像

Update 2 Problems with formGroup with formGroup. SOLVED

NgControl only take account the controls that has [(ngModel)], formControlName and [formControl], so. If we can use a form like

我们可以使用如下形式:

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) }) })

We can use a form like:

<按钮>点击</按钮></表单>

<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 中的位置

where in .ts we has

get group()
  {
    return this.myForm.get('group')
  }

Update 3 使用 Angular 8 可以得到孩子的后代,所以简单写

Update 3 with Angular 8 you can get the descendants of the children, so it's simply write

 @ContentChildren(NgControl,{descendants:true}) fields: QueryList<NgControl>

这篇关于Angular 自定义焦点指令.聚焦表单的第一个无效输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆