Angular 6 Reactive Forms: Как установить фокус на первый неверный ввод - PullRequest
0 голосов
/ 25 декабря 2018

В моем приложении 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: [''],
});

Я пробовал директиву с автофокусировкой , но она не сработала

Предложения?

Ответы [ 4 ]

0 голосов
/ 02 июля 2019

Попробуйте это:

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 вашей собственной формой, как это случилось со мной, так что посмотрите правильно, в каком поле он сообщает первым, и установите правильную позицию.

0 голосов
/ 26 декабря 2018

Я сделал это с помощью директив.Таким образом, моя форма будет выглядеть так:

<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 будет входной.

0 голосов
/ 08 мая 2019

Эта опция не работает для меня, но мне удалось исправить это, изменив код следующим образом:

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

}
0 голосов
/ 25 декабря 2018

Мой ответ вдохновлен yurzui ответом здесь.Я использую логику из его ответа, чтобы получить nativeElement определенного FormControl, используя его FormControl.

Это логика, которая делает это:

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 вместо Array.forEach, так как хотел вырваться из цикла.

Надеюсь, это поможет вам.

Вот Рабочий образец StackBlitz для вашей ссылки.

...