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

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

问题描述

我创建了一个指令以使输入无效(如果输入无效)

  import'@ angular/core'中的{指令,输入,Renderer2,ElementRef,OnChanges};@指示({//tslint:disable-next-line:directive-selector选择器:"[focusOnError]"})导出类HighlightDirective实现OnChanges {@Input()提交:字符串;构造函数(私有渲染器:Renderer2,私有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());}}} 

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

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

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

预期结果:-如果两个输入均无效,则在提交表单后,仅应集中第一个输入.

当前结果:-如果两个输入均无效,则在提交表单后,第二个输入将成为焦点.

我不知道如何指定只有在第一个孩子的情况下才这样做",我尝试使用该指令的选择器没有运气.

有什么想法吗?

非常感谢.

解决方案

要控制Form的输入,我认为更好的解决方案是使用ViewChildren获取所有元素.因此,我们可以遍历这些元素,然后将焦点放在第一个元素上.

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

  @Directive({选择器:"[focusOnError]"})导出类FocusOnErrorDirective {公开获取无效(){返回this.control?this.control.invalid:false;}公众关注{this.el.nativeElement.focus()}构造函数(@Optional()私有控件:NgControl,私有el:ElementRef){}} 

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

  @ViewChildren(FocusOnErrorDirective)字段:QueryList< FocusOnErrorDirective>查看() {const fields = this.fields.toArray();为(让字段的字段){如果(field.invalid){field.focus();休息;}}} 

您可以在 stackblitz

更新总是可以改善的地方:

为什么不创建适用于表格的指令?

  @Directive({选择器:"[focusOnError]"})导出类FocusOnErrorDirective {@ContentChildren(NgControl)字段:QueryList< NgControl>@HostListener('提交')查看() {const字段= this.fields.toArray();对于(让字段的字段){如果(field.invalid){(field.valueAccessor为任意值)._ elementRef.nativeElement.focus();休息;}}} 

所以,我们的.html就像

 < form [formGroup] ="myForm"focusOnError><输入类型=文本";formControlName =" familyName"/><输入类型=文本";formControlName ="appointmentCode";/>< button>单击</button></form> 

请参见 stackblitz

更多,如果我们将其用作选择器表单

  @Directive({选择器:形式"}) 

即使我们可以删除表单中的focusOnError

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

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

NgControl仅考虑具有[(ngModel)],formControlName和[formControl]的控件.如果我们可以使用类似

的表格

  myForm = new FormGroup({familyName:new FormControl('',Validators.required),subscriptionCode:new FormControl('',Validators.required),组:新的FormGroup({subfamilyName:new FormControl('',Validators.required),subappointmentCode:new FormControl('',Validators.required)})}) 

我们可以使用如下形式:

 < form [formGroup] ="myForm"focusOnError(submit)="submit(myForm)"<输入类型=文本";formControlName =" familyName"/><输入类型=文本";formControlName ="appointmentCode";/>< div><输入类型=文本";[formControl] ="group.get('subfamilyName')"/><输入类型=文本";[formControl] ="group.get('subappointmentCode')"/></div>< button>单击</button></form> 

.ts中的哪里

  get group(){返回this.myForm.get('group')} 

更新3 并使用Angular 8可以获得孩子的后代,因此只需编写

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

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.

Any ideas?

Thanks a lot in advance.

解决方案

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

You can see in action in the stackblitz

UPDATE always the things can improve:

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

So, our .html it's like

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

See the stackblitz

Even more, if we use as selector form

@Directive({
  selector: 'form'
})

Even we can remove the focusOnError in the form

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

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>

where in .ts we has

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

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>

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

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