Предупреждения об ошибках в угловых реактивных формах появляются на шаг позже - PullRequest
2 голосов
/ 25 октября 2019

Я использую Angular 8 и пытаюсь создать регистрационную форму с реактивными формами. Я создал несколько предупреждений для отображения ошибок проверки.

Однако вместо текущего предупреждения отображается предыдущее предупреждение! (с опозданием на один шаг)

app.component.ts файл:

    import { Component } from '@angular/core';
    import { FormBuilder, Validators, FormControl } from '@angular/forms';

    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent  {

      form = this.fBuilder.group({
        userName: ['', [
          Validators.required,
          Validators.minLength(3),
          this.userNameValidation.bind(this)
        ]]
      });

      requiredError: boolean;
      minLengthError: boolean;

      constructor(private fBuilder: FormBuilder) { }

      // User Name Validation
      userNameValidation(control: FormControl) {
        if (control.hasError('required') && control.dirty) {
          this.requiredError = true;
        } else {
          this.requiredError = false;
        }

        if (control.hasError('minlength') && control.dirty) {
          this.minLengthError = true;
        } else {
          this.minLengthError = false;
        }
      }
    }

app.component.html файл:

    <form [formGroup]="form">
      <label>User Name: </label>
        <input formControlName="userName" type="text">
    </form>

    <!-- alerts -->
    <p *ngIf="requiredError">User Name is required</p>
    <p *ngIf="minLengthError">User Name must be at least 3 characters</p>

Вот простой StackBlitz, показывающий, что я имею в виду:

Stackblitz Пример ??

Попробуйте ввести одну букву, затем удалитеэто и посмотрим, что получится.

Заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 25 октября 2019

Вам не нужен специальный валидатор для отображения ошибок в ваших формах. То, что вы делаете с this.userNameValidation.bind(this), создает пользовательский валидатор.

Что вы можете сделать, это создать переменную в вашем компоненте (файл .ts) для ссылки на элемент управления формы в вашей группе форм.

В этом случае get userName() { return this.form.get('userName'); }.

Это создает переменную userName для вашего шаблона "get". Впоследствии вы можете использовать эту переменную для проверки на наличие ошибок, таких как:

template .html file:

<form [formGroup]="form">
  <label for="userName">User Name: </label>

  <input type="text" formControlName="userName" name="userName">
  <br>
  <ng-container *ngIf="userName.errors?.required && (userName?.touched || userName?.dirty)">
    <small class="formError">User Name is required!</small>
  </ng-container>
  <ng-container *ngIf="userName.errors?.minlength && (userName?.touched || userName?.dirty)">
    <small class="formError">User Name must be at least 3 characters!</small>
  </ng-container>
  <br>
</form>

Как видите, userName.errors?.minlength и userName.errors?.required будут напрямую ссылатьсяuserName в вашем файле компонентов. Вы также хотите проверить .touched и .dirty, потому что вы не хотите отображать ошибку только до тех пор, пока ваши пользователи не взаимодействуют с элементом управления формой.

Для дальнейшего использования прочитайте Официальные документы на английском языке по проверке реактивной формы (Примечание: читать только первую часть , следующий раздел в формах на основе шаблонов)

Вы также должны использовать <ng-container>, потому что* ngIf отобразит элементы в вашей DOM, даже если * ngIf оценивается как false. См. Это Угловой: Элемент ng-контейнера

компонент .ts файл

import { Component } from '@angular/core';
import { FormBuilder, Validators, FormControl, FormGroup } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  // requiredError: boolean; //not required
  // minLengthError: boolean; //not required

  form: FormGroup;

  constructor(private fBuilder: FormBuilder) { }

  get userName() { return this.form.get('userName'); } //create a userName variable for template to reference

  ngOnInit(){
    this.form = this.fBuilder.group({ 
      userName: [
        '', [ Validators.required, Validators.minLength(3)]
      ]
    });
  }

  ngAfterViewChecked(){
    console.log(this.userName.errors)
  }

Пример разветвленного стекаблика ⚡⚡

Надеюсь, это помогло!

1 голос
/ 27 октября 2019

Исходя из комментария к другому ответу, вы хотите «отправить ошибки другому компоненту». Если вам действительно нужен специальный валидатор для этого, мы должны помнить, что угловые формы на самом деле асинхронны, поэтому для правильной оценки формы требуется дополнительный тик. Я бы никогда не рекомендовал использовать setTimeout в асинхронных функциях, но мы можем знать, что значения формы были установлены после ожидания тика, так что это безопасно для использования. Поэтому оберните все в тайм-аут:

setTimeout(() => {
  if (control.hasError("required") && control.dirty) {
    this.requiredError = true;
  } else {
    this.requiredError = false;
  }

  if (control.hasError("minlength") && control.dirty) {
    this.minLengthError = true;
  } else {
    this.minLengthError = false;
  }
});

STACKBLITZ

Но если у вас есть дочерний компонент, такой как <hello></hello> в вашем шаблоне ивы хотите отправить ошибки этому потомку через @Input, вам не нужно , нужно , чтобы использовать вышеупомянутый подход, вы также можете просто отправить логическое значение валидности потомку, например ...

<hello *ngIf="form.get('userName').dirty" [requiredError]="form.hasError('required', 'userName')"></hello>

и поймайте это у вашего ребенка, например:

@Input() requiredError: boolean;

ngOnChanges() {
  if (this.requiredError) {
    alert('field required!')
  }
}

STACKBLITZ

...