Angular 未显示反应式表单验证消息

Angular Reactive Forms Validation Messages Not Showing

我正在使用 Angular 8,并且我在注册页面中使用了 Reactive 表单。并且还使用 Angular Material Stepper Ui 来设计表单。

这是 signup.component.ts 文件。

import { Component, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators, AbstractControl } from '@angular/forms';
import { UserSignUp } from '../shared/signupForm';
import { AuthService } from '../services/auth.service';

@Component({
  selector: 'app-signup',
  templateUrl: './signup.component.html',
  styleUrls: ['./signup.component.scss']
})
export class SignupComponent implements OnInit {

  signupForm: FormGroup;
  signup: UserSignUp;
  @ViewChild('form', {
    static: true
  }) signupFormDirective;
  errMsg = '';
  isSuccessful = false;
  isLoginFailed = false;
  isLinear = true;

  formErrors = {
    'username': '',
    'password': '',
    'email': '',
    'firstName' : '',
    'lastName' : '',
    'designation': '',
    'organization': '',
    'address': '',
    'contactNo': ''
  };

  validationMessages = {
    'username' : {
      'required'  :   'Username Name is Required.',
      'minlength' :   'Username must be at least 3 characters long..',
      'maxlength' :   'Username cannot be more than 25 characters long'
    },
    'password' : {
      'required'  :   'Password is required',
      'minlength' :   'Password must be at least 5 Characters',
      'maxlength' :   'Password cannot be more than 25 characters long'
    },
    'email' : {
      'required'  :   'Email is Required.',
      'email'     :   'Invalid Email'
    },
    'firstName' : {
      'required'  :   'First Name is required'
    },
    'lastName' : {
      'required'  :   'Last Name is required.'
    },
    'designation' : {
      'required'  :   'Designation is Required.'
    },
    'organization' : {
      'required'  :   'Organization is Required.'
    },
    'address' : {
      'required'  :   'First Name is Required.'
    },
    'ContactNo' : {
      'required'  :   'First Name is Required.',
      'pattern'   :   'Contact No. should only contain Numbers '
    }
  };


  constructor(private fb: FormBuilder, private authService: AuthService) {
    this.createForm();
   }

  ngOnInit() {}

  get formArray(): AbstractControl | null { return this.signupForm.get('formArray'); }


  createForm() {
    this.signupForm = this.fb.group({
      formArray: this.fb.array([
        this.fb.group({
          firstName: ['', [Validators.required]],
          lastName: ['', [Validators.required]],
          username : ['', [Validators.required, Validators.minLength(3), Validators.maxLength(25)]],
          email: ['', [Validators.required, Validators.email]],
          designation: ['', [Validators.required]]
        }),
        this.fb.group({
          password : ['', [Validators.required, Validators.minLength(5), Validators.maxLength(25)]],
          organization: ['', [Validators.required]],
          address: ['', [Validators.required]],
          contactNo: ['', [Validators.required]]
        }),
      ])
    });

    this.signupForm.valueChanges
      .subscribe(data => this.onValueChanged(data));

    this.onValueChanged();

  }

  onValueChanged(data?: any) {
    if (!this.signupForm) { return ; }
    const form = this.signupForm;
    for ( const field in this.formErrors) {
      if (this.formErrors.hasOwnProperty(field)) {
        this.formErrors[field] = '';
        const control = form.get(field);
        if (control && control.dirty && !control.valid) {
          const messages = this.validationMessages[field];
          for (const key in control.errors) {
              if (control.errors.hasOwnProperty(key)) {
                this.formErrors[field] += messages[key] + ' ';
              }
          }
        }
      }
    }
  }

  onSubmit() {
    this.signup = this.signupForm.value;
    console.log(this.signup);
    this.authService.register(this.signup)
    .subscribe(
      data => {
        console.log(data);
        this.isSuccessful = true;
        console.log('Successful');
      },
      err => {
        this.errMsg = err.error.message;
        this.isLoginFailed = true;
      }
    );

    this.signupForm.reset({
      username: '',
      password: '',
      email: '',
      firstName: '',
      lastName: '',
      designation: '',
      organization: '',
      address: '',
      contactNo: ''
    });
    this.signupFormDirective.resetForm();
  }



}

这是 signup.component.html 文件。

<div class="container" style="height: 45px;"></div>

<div fxLayoutAlign="space-around center" class="container" >
  <mat-card>
    <div fxLayoutAlign="center">
      <h1>Sign Up</h1>
    </div>
<form novalidate [formGroup]="signupForm" #form="ngForm" (ngSubmit)="onSubmit()">
  <mat-horizontal-stepper [linear]="isLinear"  formArrayName="formArray">
    <mat-step formGroupName="0" [stepControl]="formArray?.get([0])">
        <ng-template matStepLabel>Fill Out Your Details</ng-template>
        <mat-form-field >
          <input matInput formControlName="firstName" placeholder="First Name" type="text" required>
          <mat-error *ngIf="formErrors.firstName">
            {{formErrors.firstName}}
          </mat-error>
        </mat-form-field>
        <mat-form-field >
          <input matInput formControlName="lastName" placeholder="Last Name" type="text" required>
          <mat-error *ngIf="formErrors.lastName">
            {{formErrors.lastName}}
          </mat-error>
        </mat-form-field>
        <p><mat-form-field >
          <input matInput formControlName="username" placeholder="Username" type="text" required>
          <mat-error *ngIf="formErrors.username">
            {{formErrors.username}}
          </mat-error>
        </mat-form-field></p>
        <p><mat-form-field >
          <input matInput formControlName="email" placeholder="Email" type="email" required>
          <mat-error *ngIf="formErrors.email">
            {{formErrors.email}}
          </mat-error>
        </mat-form-field></p>
        <p><mat-form-field >
          <input matInput formControlName="designation" placeholder="Designation" type="text" required>
          <mat-error *ngIf="formErrors.designation">
            {{formErrors.designation}}
          </mat-error>
        </mat-form-field></p>
        <div>
          <button mat-raised-button matStepperNext type="button">Next</button>
        </div>
    </mat-step>
    <mat-step formGroupName="1" [stepControl]="formArray?.get([1])" >
        <ng-template matStepLabel>Few More Steps</ng-template>
        <mat-form-field >
          <input matInput formControlName="password" placeholder="Password" type="password" required>
          <mat-error *ngIf="formErrors.password">
            {{formErrors.password}}
          </mat-error>
        </mat-form-field>
        <p><mat-form-field >
          <input matInput formControlName="organization" placeholder="Organization" type="text" required>
          <mat-error *ngIf="formErrors.organization">
            {{formErrors.organization}}
          </mat-error>
        </mat-form-field></p>
        <p><mat-form-field >
          <textarea matInput formControlName="address" placeholder="Address" type="text" rows="3" cols="10" required ></textarea>
          <mat-error *ngIf="formErrors.address">
            {{formErrors.address}}
          </mat-error>
        </mat-form-field></p>
        <p><mat-form-field >
          <input matInput formControlName="contactNo" placeholder="Contact Number" type="number" required>
          <mat-error *ngIf="formErrors.contactNo">
            {{formErrors.contactNo}}
          </mat-error>
        </mat-form-field></p>
        <div>
          <button mat-raised-button matStepperPrevious class="button-space" type="button">Back</button>
          <button mat-raised-button matStepperNext class="button-space" type="button">Next</button>
        </div>
    </mat-step>
    <mat-step>
      <ng-template matStepLabel>Done</ng-template>
        <p>You are now done.</p>
          <div>
            <button mat-raised-button matStepperPrevious class="button-space">Back</button>
            <button type="submit" mat-raised-button color="primary" class="button-space" [disabled]="signupForm.invalid">Submit</button>
          </div>
    </mat-step>
  </mat-horizontal-stepper>
</form>
</mat-card>
</div>

验证正确运行。 (当输入有效的电子邮件时,表单字段变为红色)但是验证消息不是 shown.It 在添加 angular material 步进器之前是完美的工作。当我添加步进器时,我不得不更改表单组结构并添加表单数组并将表单分成几部分。之后发生了这个错误。

您是否已经在发送请求之前尝试验证并在表单无效时将表单标记为已触及? 像这样:


if(this.signupForm.valid) {
  // send request here
} else {
  this.signupForm.markAllAsTouched()
}

我认为你的做法是错误的。输入错误触摸时显示mat-form-field里面的mat-error。如果你想显示错误,你可以使用例如

对于具有唯一错误的输入

<mat-form-field >
   <input matInput formControlName="firstName" placeholder="First Name" type="text" required>
   <mat-error >
      {{validationMessages.firstName}}
   </mat-error>
</mat-form-field>

对于有更多错误的输入

<mat-form-field >
   <input matInput formControlName="username" placeholder="Username" type="text" required>
    <mat-error>
      <span *ngFor="let error of signupForm.get('username').errors|keyvalue">
         {{validationMessages.username[error.key]}}
    </span>
  </mat-error>
</mat-form-field>

而且您可以忘记订阅更改。看到,在最后一种情况下,我们迭代了作为对象的 signupForm.get('username').errors - 这就是使用 keyvalue 管道的原因。使用键值管道,error.key 变成获取值,"required","minlength" 或 "maxlength"