Angular 6反应形式:如何将重点放在第一个无效输入上

时间:2018-12-25 17:40:47

标签: javascript angular html5 rxjs angular-reactive-forms

在我的 Angular 6 应用中,我正在使用反应形式

我的目的是在提交时,我想将重点放在出现错误时的第一个无效输入上。

我的表单如下:

<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 obligatoire"
                 [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 obligatoire"
                 [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 obligatoire"
                 [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>

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

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

我已经尝试过 autofocus 指令,但这没用

建议?

6 个答案:

答案 0 :(得分:4)

“我的答案”的灵感来自yurzuianswer。我正在使用他的回答中的逻辑,通过使用特定的nativeElement来获取特定FormControl的{​​{1}}。

这是这样做的逻辑:

FormControl

现在,即使表单的错误字段无效,其错误字段也将为null。因此,要获取确切的第一个无效字段,我们必须遍历所有字段并检查每个字段的有效性。我可以在const originFormControlNameNgOnChanges = FormControlName.prototype.ngOnChanges; FormControlName.prototype.ngOnChanges = function () { const result = originFormControlNameNgOnChanges.apply(this, arguments); this.control.nativeElement = this.valueAccessor._elementRef.nativeElement; return result; }; 方法中编写此逻辑。像这样:

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; } } } 而不是for

希望这可以为您解决问题。

  

这是您推荐的Working Sample StackBlitz

答案 1 :(得分:2)

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

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

以及该指令本身的代码:

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

但是,此解决方案并不完整,因为有很多极端情况需要考虑。例如,如果第一个元素是单选按钮组,该怎么办。调度焦点事件将自动标记该字段。其次,并非每个角度广告ng-invalid都会被输入。

答案 2 :(得分:2)

我们只需在表单的commit()中编写此代码即可将重点放在第一个无效输入上。

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

    }

答案 3 :(得分:0)

该选项对我不起作用,但是我设法通过如下代码进行了更改来修复它:

@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();
    }
  }

}

答案 4 :(得分:0)

尝试一下:

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

请记住进行调试,看看元素0是否不是您自己遇到的形式,因此请正确查看它报告的第一个字段并将其放在正确的位置。

答案 5 :(得分:0)

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

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将是您的FormGroup。

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