我想执行表格验证.如果字段是"肮脏的".

  1. 如果密码字段中没有内容,则应显示错误.

  2. 如果密码不匹配,也应该显示错误.

你能给我解释一下我的代码有什么问题吗?我已经创建了一个代码示例:

Minimal Reproducible Stackblitz

完整代码:

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import {
  AbstractControl,
  FormControl,
  FormGroup,
  ReactiveFormsModule,
  Validators,
} from '@angular/forms';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatButtonModule } from '@angular/material/button';
import { FormsModule } from '@angular/forms';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [
    ReactiveFormsModule,
    MatInputModule,
    MatFormFieldModule,
    MatCheckboxModule,
    MatButtonModule,
    FormsModule,
  ],
  template: `
    <form [formGroup]="registerForm">
      <mat-form-field>
          <mat-label>Password</mat-label>
          <input matInput formControlName="password" type="password"> 
          @if (registerForm.get('password').hasError('required') && registerForm.get('password').dirty) {
          <mat-error>Password is required</mat-error> }
      </mat-form-field>

      <mat-form-field>
          <mat-label>Confirm Password</mat-label>
          <input matInput formControlName="confirmPassword" type="password"> @if (registerForm.errors?.['mismatch'] && registerForm.dirty) {
          <mat-error>Password does not match</mat-error> }
      </mat-form-field>


      <button mat-raised-button color="primary " type="submit" [disabled]="!registerForm.valid">Sign up</button>
</form>
  `,
})
export class App {
  name = 'Angular';
  registerForm: FormGroup;

  constructor() {
    this.registerForm = new FormGroup(
      {
        password: new FormControl('', [
          Validators.required,
          Validators.minLength(6),
        ]),
        confirmPassword: new FormControl('', [Validators.required]),
      },
      { validators: this.passwordMatchValidator }
    );
  }

  private passwordMatchValidator(control: AbstractControl) {
    return control.get('password')?.value ===
      control.get('confirmPassword')?.value
      ? null
      : { mismatch: true };
  }
}

bootstrapApplication(App, {
  providers: [provideAnimationsAsync()],
});

我使用Angular 17和Angular Metal.

推荐答案

我们可以使用?. typescript安全操作符来防止访问属性时HTML中出现任何错误.需要注意的事项:

  1. 我们已经在表单级别设置了mismatch验证器要验证,但我们在确认密码表单字段显示错误消息,所以我们需要通知表单控件该元素处于错误状态,为此我们可以使用errorStateMatcher输入绑定来更新表单,这将显示错误!

错误状态匹配器代码!

export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(
    control: FormControl | null,
    form: FormGroupDirective | NgForm | null
  ): boolean {
    return !!(form?.errors?.['mismatch'] && control?.touched);
  }
}
...

...
export class App {
  name = 'Angular';
  registerForm: FormGroup;
  matcher = new MyErrorStateMatcher();

HTML

...
<input matInput formControlName="confirmPassword" type="password" [errorStateMatcher]="matcher"> 
...
  1. 我们可以使用@switch而不是@if,因为我们通常一次显示一个错误,所以如果我们使用switch,代码就会更少

请在下面找到完整的代码和工作stackblitz以供参考!

完整代码:

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import {
  AbstractControl,
  FormControl,
  FormGroup,
  NgForm,
  ReactiveFormsModule,
  Validators,
  FormGroupDirective,
} from '@angular/forms';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatButtonModule } from '@angular/material/button';
import { FormsModule } from '@angular/forms';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { CommonModule } from '@angular/common';
import { ErrorStateMatcher } from '@angular/material/core';

export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(
    control: FormControl | null,
    form: FormGroupDirective | NgForm | null
  ): boolean {
    return !!(form?.errors?.['mismatch'] && control?.touched);
  }
}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [
    ReactiveFormsModule,
    MatInputModule,
    MatFormFieldModule,
    MatCheckboxModule,
    MatButtonModule,
    FormsModule,
    CommonModule,
  ],
  template: `
    <form [formGroup]="registerForm">
      <mat-form-field>
          <mat-label>Password</mat-label>
          <input matInput formControlName="password" type="password"> 
          @if (registerForm?.get('password')?.touched) {
            <mat-error>
            @switch (true) {
                @case (registerForm.get('password')?.hasError('required')) {
                  Password is required
                }
                @case (registerForm.get('password')?.hasError('minlength')) {
                  Password must be 6 characters in length
                }
            }
          </mat-error>
          }
      </mat-form-field>

      <mat-form-field>
          <mat-label>Confirm Password</mat-label>
          <input matInput formControlName="confirmPassword" type="password" [errorStateMatcher]="matcher"> 
          @if (registerForm?.get('confirmPassword')?.touched) {
            <mat-error>
            @switch (true) {
                @case (registerForm.get('confirmPassword')?.hasError('required')) {
                  Confirm Password is required
                }
                @case (registerForm.errors?.['mismatch']) {
                  Password does not match
                }
            }
          </mat-error>
          }
      </mat-form-field>


      <button mat-raised-button color="primary " type="submit" [disabled]="!registerForm.valid">Sign up</button>
</form>
  `,
})
export class App {
  name = 'Angular';
  registerForm: FormGroup;
  matcher = new MyErrorStateMatcher();

  constructor() {
    this.registerForm = new FormGroup(
      {
        password: new FormControl('', [
          Validators.required,
          Validators.minLength(6),
        ]),
        confirmPassword: new FormControl('', [Validators.required]),
      },
      { validators: this.passwordMatchValidator }
    );
  }

  private passwordMatchValidator(control: AbstractControl) {
    return control.get('password')?.value ===
      control.get('confirmPassword')?.value
      ? null
      : { mismatch: true };
  }
}

bootstrapApplication(App, {
  providers: [provideAnimationsAsync()],
});

Stackblitz Demo

Angular相关问答推荐

浏览器中的控制台根据折叠度同时显示字段的两个不同值

Angular material 输入字段中的图标未显示

PrimeNG侧栏清除primeNG消息.为什么?

基于另一个控制值显示值的Angular 数组

ANGLE DI useFactory将参数传递给工厂函数

Angular 16-错误NG8002:无法绑定到NGModel,因为它不是输入的已知属性

我正在try 将一个带有模块联盟的Angular 8项目expose 到另一个Angular 项目,Angular 是15,这可能吗?如果是这样,有什么建议吗?

nx serve正在忽略@angular/localize/init的导入"

ngx-http-client 在 Angular 16 中已弃用

Angular CLI 与 Angular 版本不兼容

Angular 16:信号更新未能更新视图

Angular 测试被认为是成功的,即使有错误

使用 BehaviorSubject 从服务更新 Angular 组件

等待两个订阅完成而不嵌套

刷新页面导致 401 错误-Angular 8

为什么 HttpParams 在 Angular 4.3 中的多行中不起作用

Subject.complete() 是否取消订阅所有听众?

如何检测滚动到html元素的底部

ng test 和 ng e2e 之间的真正区别是什么

缺少带有Angular的语言环境XXX的语言环境数据