You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular表单中添加自定义验证器及密码匹配校验

问题描述

我有如下接口文件userslist.ts:

export interface Userslist {
    id: number;
    fname: string;
    lname: string;
    email: string;
    pas1: string;
    pas2: string;
}

我使用该接口获取包含名字、姓氏、邮箱、密码及确认密码的表单数据,另外两个文件如下:

ucreate.component.ts:

import { Component, ViewChild, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Userslist } from '../userslist';
import { UserslistService } from '../userslist.service';

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

  userForm: Userslist = {
    id: 0,
    fname: '',
    lname: '',
    email: '',
    pas1: '',
    pas2: '',
  };

  constructor(private userlistService: UserslistService, private router: Router) { }

  ngOnInit(): void {
  }

  create(){
    this.userlistService.create(this.userForm)
    .subscribe({
      next:(data) => {
        this.router.navigate(["/userslist/adminhome"])
      },
      error:(err) => {
        console.log(err);
      }
    })
  }
}

ucreate.component.html:

<div class="container">
    <legend>Create Item</legend>
    <form>
      <div class="mb-3">
        <label for="txtName" class="form-label">First Name</label>
        <input type="text" name="fname" [(ngModel)] = "userForm.fname" class="form-control" id="txtName" />
      </div>
      <div class="mb-3">
        <label for="txtName" class="form-label">Last Name</label>
        <input type="text" name="lname" [(ngModel)] = "userForm.lname" class="form-control" id="txtName" />
      </div>
      <div class="mb-3">
        <label for="txtName" class="form-label">e-mail</label>
        <input type="text" name="email" [(ngModel)] = "userForm.email" class="form-control" id="txtName" />
      </div>
      <div class="mb-3">
        <label for="txtName" class="form-label">Password</label>
        <input type="text" name="pas1" [(ngModel)] = "userForm.pas1" class="form-control" id="txtName" />
      </div>
      <div class="mb-3">
        <label for="txtName" class="form-label">Confirm Password</label>
        <input type="text" name="pas2" [(ngModel)] = "userForm.pas2" class="form-control" id="txtName" />
      </div>
      <button type="button" (click)="create()" class="btn btn-primary">Create Account</button>
    </form>
  </div>

请问如何为上述输入字段添加自定义验证,以及如何显示两次输入的密码是否匹配?


解决方案

推荐使用Angular响应式表单实现验证,它比模板驱动表单更灵活,适合自定义验证场景。

步骤1:修改ucreate.component.ts文件

导入响应式表单模块,创建表单控件并添加内置验证器,同时自定义密码匹配验证函数:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Userslist } from '../userslist';
import { UserslistService } from '../userslist.service';

// 自定义密码匹配验证器
function passwordMatchValidator(form: FormGroup) {
  const password = form.get('pas1')?.value;
  const confirmPassword = form.get('pas2')?.value;
  return password === confirmPassword ? null : { mismatch: true };
}

@Component({
  selector: 'app-ucreate',
  templateUrl: './ucreate.component.html',
  styleUrls: ['./ucreate.component.css']
})
export class UcreateComponent implements OnInit {
  userForm: FormGroup;

  constructor(
    private userlistService: UserslistService, 
    private router: Router,
    private fb: FormBuilder
  ) {
    // 初始化表单并添加验证规则
    this.userForm = this.fb.group({
      id: [0],
      fname: ['', [Validators.required, Validators.minLength(2)]],
      lname: ['', [Validators.required, Validators.minLength(2)]],
      email: ['', [Validators.required, Validators.email]],
      pas1: ['', [Validators.required, Validators.minLength(6)]],
      pas2: ['', Validators.required]
    }, { validators: passwordMatchValidator });
  }

  ngOnInit(): void {
  }

  // 快捷获取表单控件,方便模板访问错误信息
  get f() {
    return this.userForm.controls;
  }

  // 提交前先验证表单有效性
  create(){
    if (this.userForm.invalid) {
      this.userForm.markAllAsTouched();
      return;
    }
    const userData: Userslist = this.userForm.value;
    this.userlistService.create(userData)
    .subscribe({
      next:(data) => {
        this.router.navigate(["/userslist/adminhome"])
      },
      error:(err) => {
        console.log(err);
      }
    })
  }
}

步骤2:修改ucreate.component.html文件

更新模板绑定响应式表单,添加错误提示和密码匹配状态显示:

<div class="container">
    <legend>Create Item</legend>
    <form [formGroup]="userForm">
      <!-- 名字输入框 -->
      <div class="mb-3">
        <label for="fname" class="form-label">First Name</label>
        <input 
          type="text" 
          formControlName="fname" 
          class="form-control" 
          id="fname" 
          [ngClass]="{ 'is-invalid': f.fname.touched && f.fname.invalid }"
        />
        <div *ngIf="f.fname.touched && f.fname.invalid" class="invalid-feedback">
          <div *ngIf="f.fname.errors?.['required']">名字不能为空</div>
          <div *ngIf="f.fname.errors?.['minlength']">名字长度不能少于2位</div>
        </div>
      </div>

      <!-- 姓氏输入框 -->
      <div class="mb-3">
        <label for="lname" class="form-label">Last Name</label>
        <input 
          type="text" 
          formControlName="lname" 
          class="form-control" 
          id="lname" 
          [ngClass]="{ 'is-invalid': f.lname.touched && f.lname.invalid }"
        />
        <div *ngIf="f.lname.touched && f.lname.invalid" class="invalid-feedback">
          <div *ngIf="f.lname.errors?.['required']">姓氏不能为空</div>
          <div *ngIf="f.lname.errors?.['minlength']">姓氏长度不能少于2位</div>
        </div>
      </div>

      <!-- 邮箱输入框 -->
      <div class="mb-3">
        <label for="email" class="form-label">e-mail</label>
        <input 
          type="email" 
          formControlName="email" 
          class="form-control" 
          id="email" 
          [ngClass]="{ 'is-invalid': f.email.touched && f.email.invalid }"
        />
        <div *ngIf="f.email.touched && f.email.invalid" class="invalid-feedback">
          <div *ngIf="f.email.errors?.['required']">邮箱不能为空</div>
          <div *ngIf="f.email.errors?.['email']">请输入有效的邮箱格式</div>
        </div>
      </div>

      <!-- 密码输入框 -->
      <div class="mb-3">
        <label for="pas1" class="form-label">Password</label>
        <input 
          type="password" 
          formControlName="pas1" 
          class="form-control" 
          id="pas1" 
          [ngClass]="{ 'is-invalid': f.pas1.touched && f.pas1.invalid }"
        />
        <div *ngIf="f.pas1.touched && f.pas1.invalid" class="invalid-feedback">
          <div *ngIf="f.pas1.errors?.['required']">密码不能为空</div>
          <div *ngIf="f.pas1.errors?.['minlength']">密码长度不能少于6位</div>
        </div>
      </div>

      <!-- 确认密码输入框 -->
      <div class="mb-3">
        <label for="pas2" class="form-label">Confirm Password</label>
        <input 
          type="password" 
          formControlName="pas2" 
          class="form-control" 
          id="pas2" 
          [ngClass]="{ 'is-invalid': (f.pas2.touched && f.pas2.invalid) || userForm.hasError('mismatch') }"
        />
        <div *ngIf="f.pas2.touched && f.pas2.invalid" class="invalid-feedback">
          <div *ngIf="f.pas2.errors?.['required']">请确认密码</div>
        </div>
        <div *ngIf="userForm.hasError('mismatch') && f.pas2.touched" class="text-danger small">
          两次输入的密码不匹配
        </div>
      </div>

      <button 
        type="button" 
        (click)="create()" 
        class="btn btn-primary"
        [disabled]="userForm.invalid"
      >Create Account</button>
    </form>
  </div>

关键说明

  1. 响应式表单优势:通过FormBuilder集中管理验证规则,逻辑清晰易维护。
  2. 内置验证器:使用Validators.required(必填)、Validators.minLength(最小长度)、Validators.email(邮箱格式)等内置规则。
  3. 自定义密码验证:通过全局表单验证器对比密码与确认密码的值,返回验证结果。
  4. 错误提示:用[ngClass]给无效控件添加样式,通过*ngIf判断控件状态和错误类型,显示对应提示。
  5. 提交拦截:提交前检查表单有效性,无效时标记所有控件为已触碰并终止提交。

内容的提问来源于stack exchange,提问作者AnkaDel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 17:22:05