javascript Angular 6 Reactive Forms:如何将焦点设置在第一个无效输入上

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/53924414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:19:58  来源:igfitidea点击:

Angular 6 Reactive Forms : How to set focus on first invalid input

javascriptangularhtmlrxjsangular-reactive-forms

提问by firasKoubaa

Under my Angular 6app , i'm using Reactive Forms.

在我的Angular 6应用程序下,我使用的是Reactive Forms

My purpose is when submitting , i want to set focus on first invalid input when error.

我的目的是在提交时,我想在出错时将焦点设置在第一个无效输入上。

My form looks like this :

我的表格是这样的:

<form [formGroup]="addItemfForm " (ngSubmit)="onSubmitForm()">

        <div class="form-inline form-group">
          <label class="col-md-2 justify-content-start">
            Libellé du pef
            <span class="startRequired mr-1"> *</span>
          </label>
          <input type="text"
                 maxlength="100"
                 formControlName="libellePef"
                 class="col-md-6 form-control"
                 placeholder="saisie obligattheitroade"
                 [ngClass]="{ 'is-invalid': submitted && formFiels.libellePef.errors }"/>
          <div *ngIf="submitted && formFiels.libellePef.errors" class="col invalid-feedback">
            <div class="col text-left" *ngIf="formFiels.libellePef.errors.required">Libellé du pef est requis.</div>
          </div>
        </div>

        <div class="form-inline form-group">
          <label class="col-md-2 justify-content-start">
            Code Basicat
            <span class="startRequired mr-1"> *</span>
          </label>
          <input type="text"
                 maxlength="100"
                 formControlName="codeBasicat"
                 class="col-md-3 form-control"
                 placeholder="saisie obligattheitroade"
                 [ngClass]="{ 'is-invalid': submitted && formFiels.codeBasicat.errors }"/>
          <div *ngIf="submitted && formFiels.codeBasicat.errors" class="col invalid-feedback">
            <div class="text-left" *ngIf="formFiels.codeBasicat.errors.required">Code Basicat est requis.</div>
          </div>
        </div>

        <div class="form-inline form-group">
          <label class="col-md-2 justify-content-start">
            Nom de l'application
            <span class="startRequired mr-1"> *</span>
          </label>
          <input type="text"
                 maxlength="100"
                 formControlName="nomApplication"
                 class="col-md-6 form-control"
                 placeholder="saisie obligattheitroade"
                 [ngClass]="{ 'is-invalid': submitted && formFiels.nomApplication.errors }"/>
          <div *ngIf="submitted && formFiels.nomApplication.errors" class="col invalid-feedback">
            <div class="text-left" *ngIf="formFiels.nomApplication.errors.required">Nom de l'application est requis.
            </div>
          </div>
        </div>
</form>

Under my TS file , my form config looks like this :

在我的 TS 文件下,我的表单配置如下所示:

this.addItemfForm = this.formBuilder.group({
  libellePef: ['', Validators.required],
  codeBasicat: ['', Validators.required ],
  nomApplication: ['', Validators.required ],
  urlCible: [''],
  modeTransfert: [''],
});

I've tried the autofocusdirective but that didn't work

我试过自动对焦指令,但没有用

Suggestions?

建议?

采纳答案by Avinash Manohar

Use below code in your submit.

在您的提交中使用以下代码。

for (const key of Object.keys(this.addressForm.controls)) {
      if (this.addressForm.controls[key].invalid) {
        const invalidControl = this.el.nativeElement.querySelector('[formcontrolname="' + key + '"]');
        invalidControl.focus();
        break;
     }
}

this.addressForm will be your FormGroup.

this.addressForm 将是您的 FormGroup。

We don't even need directive here.

我们甚至不需要这里的指令。

回答by SiddAjmera

My Answer is inspired from yurzui's answerhere. I'm using the logic from his answer to get the nativeElementof a particular FormControlby using it's FormControl.

我的回答的灵感来自yurzui回答。我正在使用他的回答中的逻辑通过使用它来获取nativeElement特定FormControlFormControl.

This is the logic that does that:

这是这样做的逻辑:

const originFormControlNameNgOnChanges = FormControlName.prototype.ngOnChanges;
FormControlName.prototype.ngOnChanges = function () {
  const result = originFormControlNameNgOnChanges.apply(this, arguments);
  this.control.nativeElement = this.valueAccessor._elementRef.nativeElement;
  return result;
};

Now, the form's errors field would be null even though it's fields are invalid. So to get the exact first field that's invalid, we'll have to loop through all the fields and check for validity for each of them. I can write this logic in the onSubmitForm()method. Something like this:

现在,表单的错误字段将为空,即使它的字段无效。因此,要获得确切的第一个无效字段,我们必须遍历所有字段并检查每个字段的有效性。我可以在onSubmitForm()方法中写这个逻辑。像这样的东西:

onSubmitForm() {
  const fieldsToCheck = [
    'codeBasicat',
    'libellePef',
    'nomApplication'
  ];
  for (let i = 0; i < fieldsToCheck.length; i++) {
    const fieldName = fieldsToCheck[i];
    if (this.addItemfForm.get(fieldName).invalid) {
      ( < any > this.addItemfForm.get(fieldName)).nativeElement.focus();
      break;
    }
  }
}

I've deliberately used forinstead of Array.forEachas I wanted to break from the loop.

我故意使用for而不是Array.forEach因为我想打破循环。

Hopefully this should do the trick for you.

希望这对你有用。

Here's a Working Sample StackBlitzfor your ref.

这是供您参考的工作示例 StackBlitz

回答by piotr szybicki

I did that using directives. So My form would look like this:

我使用指令做到了这一点。所以我的表格看起来像这样:

<form [formGroup]="userForm" (submit)="saveData()" appFocus >
...
</form>

and the code for the directive itself:

以及指令本身的代码:

import { Directive, HostListener, Input, ElementRef } from '@angular/core';
import { NgForm } from '@angular/forms';

@Directive({
  selector: '[appFocus]'
})
export class FocusDirective {

  constructor(private el: ElementRef) { }

  @Input() formGroup: NgForm;

  @HostListener('submit', ['$event'])
  public onSubmit(event): void {
    if ('INVALID' === this.formGroup.status) {
      event.preventDefault();

      const formGroupInvalid = this.el.nativeElement.querySelectorAll('.ng-invalid');
      (<HTMLInputElement>formGroupInvalid[0]).focus();
    }
  }
}

However this solution is incomplete as there is a lot of corner cases that have to be considered. For example what if the first element is radio button group. Dispatching focus event will automatically mark the filed. Second not every element to which angular ads ng-invalid will be an input.

然而,这个解决方案是不完整的,因为需要考虑很多极端情况。例如,如果第一个元素是单选按钮组会怎样。调度焦点事件会自动标记归档。其次,并不是每个元素都会被角度广告 ng-invalid 输入。

回答by Aswathy

We can set focus on first invalid input simply by just write this code in the submit() of the form.

只需在表单的 submit() 中编写此代码,我们就可以将焦点设置在第一个无效输入上。

   if(this.form.invalid)
    {  
      // Got focus to the error field
    let invalidFields = [].slice.call(document.getElementsByClassName('ng-invalid'));
    invalidFields[1].focus();  

    }

回答by Mateus Gon?alves

Try this:

试试这个:

import { Directive, HostListener, ElementRef} from '@angular/core';

@Directive({
  selector: '[focusFirstInvalidField]'
})
export class FocusFirstInvalidFieldDirective {

  constructor(private el: ElementRef) { }

  @HostListener('submit')
  onFormSubmit() {
    const invalidElements = this.el.nativeElement.querySelectorAll('.ng-invalid');
    if (invalidElements.length > 0) {
      console.log(invalidElements[0]); 

      invalidElements[0].focus();
    }
  }
}

Remember to debug, see if element 0 is not your own form as it happened to me, so see right what field it is reporting as the first and put the position right.

记得调试,看看元素 0 是否不是你自己的表单,因为它发生在我身上,所以看看它报告的第一个字段是哪个字段,然后把位置放对。

回答by JLazar0

This option does not work for me, but I managed to fix it by changing the code as follows:

这个选项对我不起作用,但我设法通过如下更改代码来修复它:

@Directive({
  selector: '[appErrorFocusin]'
})
export class ErrorFocusinDirective {

  selectorToFocus : String = 'textArea,mat-select,select,input,button';

  constructor(private el: ElementRef,
    @Inject(DOCUMENT) private document: Document) { }

  @Input() formGroup: NgForm;

  @HostListener('submit', ['$event'])
  public onSubmit(event): void {
    if ('INVALID' === this.formGroup.status) {
      event.preventDefault();

      const formGroupInvalid = this.el.nativeElement.querySelectorAll('.ng-    invalid,:not(.mat-badge-hidden).mat-badge');
      let elementToOffset = this.getElementToOffset(formGroupInvalid[0]);
      this.document.documentElement.scrollTop = elementToOffset.offsetTop;
      this.setFocusOnError(elementToOffset);
    }
  }


  getElementToOffset(element : any){
    let defaultElement = element;
    while (!(element.parentElement instanceof HTMLFormElement)){
      if (element.parentElement){
        element = element.parentElement;
      }else{
        return defaultElement;
      }
    }
    return element;
  }

  setFocusOnError(elementToOffset : any){
    let listaElementos =     elementToOffset.querySelectorAll(this.selectorToFocus);
    if (listaElementos.length>0){
      listaElementos[0].focus();
    }
  }

}