头图

Angular 表单概述

在 Angular 中,表单有两种主要形式:模板驱动的表单和响应式表单。这段代码使用的是响应式表单(Reactive Forms),因为它更灵活,可以通过代码完全控制表单的状态和数据。响应式表单通常借助 FormBuilder 类来创建和管理表单。

代码解析

这里有两个主要部分需要解释:表单元素的创建和验证逻辑。

表单元素的创建

registerForm: UntypedFormGroup = this.fb.group(
    {
      additionalConsents:
        this.registerComponentService.generateAdditionalConsentsFormControl?.() ??
        this.fb.array([]),
    },
    {
      validators: CustomFormValidators.passwordsMustMatch(
        'password',
        'passwordconf'
      ),
    }
  );

这个注册表单具体是由 FormBuilder 实例 fb 创建的。FormBuilder 是 Angular 提供的一个帮助类,它旨在简化表单的创建。

  1. 使用 fb.group 创建表单组
    this.fb.group 方法用来创建一个 FormGroup 实例。FormGroup 是一个包含多个控件的集合,可以表示整个表单,或嵌套的表单组。
  2. 表单控件 additionalConsents
    在这个表单组中,有一个名为 additionalConsents 的控件:

    additionalConsents:
       this.registerComponentService.generateAdditionalConsentsFormControl?.() ??
       this.fb.array([]),
    • this.registerComponentService.generateAdditionalConsentsFormControl?.():这是一个方法调用,返回一个表单控件。如果该方法没有返回任何内容(即返回 nullundefined),则使用默认值 this.fb.array([])
    • this.fb.array([]):这个方法创建了一个空的 FormArrayFormArray 允许你动态管理一个数组形式的控件集合。可以想象成表单中一组动态添加的复选框或输入框。

表单验证逻辑

{
  validators: CustomFormValidators.passwordsMustMatch(
    'password',
    'passwordconf'
  ),
}

创建 FormGroup 时,第二个参数是配置对象,用于配置表单级别的验证器,这里有一个自定义的验证器 CustomFormValidators.passwordsMustMatch,它确保 passwordpasswordconf 两个控件的值必须匹配。

自定义验证器 passwordsMustMatch

通过代码可以看出,验证逻辑是通过一个自定义验证器来实现的,CustomFormValidators.passwordsMustMatch 是一个静态方法,它接收两个控件的名称:

passwordsMustMatch(password: string, confirmPassword: string) {
  return (formGroup: FormGroup) => {
    const control = formGroup.controls[password];
    const matchingControl = formGroup.controls[confirmPassword];

    if (matchingControl.errors && !matchingControl.errors.passwordsMustMatch) {
      // return if another validator has already found an error on the matchingControl
      return;
    }

    // set error on matchingControl if validation fails
    if (control.value !== matchingControl.value) {
      matchingControl.setErrors({ passwordsMustMatch: true });
    } else {
      matchingControl.setErrors(null);
    }
  }
}

在这个验证器中,它会获取到表单中的 passwordpasswordconf 两个控件,然后进行以下操作:

  1. 检查 matchingControl 是否有其它验证器的错误
    如果 matchingControl 已经有其他验证器检测到错误(且错误类型不是 passwordsMustMatch),那么这个验证器将不对它进行覆盖。
  2. 设置或清除错误

    • 如果两个控件的值不相等,则在 matchingControl 上设置一个错误 { passwordsMustMatch: true }
    • 如果值相同,则清除 matchingControl 上的错误。

这样确保了用户的两次密码输入是相同的,如果不一致,表单验证将失败。

代码举例应用

假设我们有一个注册组件 RegisterComponent,这个组件中,我们使用了上述的表单来实现用户注册。组件代码示例如下:

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

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

  registerForm: UntypedFormGroup;

  constructor(private fb: FormBuilder, private registerComponentService: RegisterComponentService) {
    this.registerForm = this.fb.group({
      username: ['', Validators.required],
      password: ['', [Validators.required, Validators.minLength(6)]],
      passwordconf: ['', Validators.required],
      additionalConsents: this.registerComponentService.generateAdditionalConsentsFormControl?.() ?? this.fb.array([])
    }, {
      validators: CustomFormValidators.passwordsMustMatch('password', 'passwordconf')
    });
  }

  onSubmit() {
    if (this.registerForm.valid) {
      console.log("Form Submitted!", this.registerForm.value);
    } else {
      console.log("Form is not valid.", this.registerForm.errors);
    }
  }
}

逐项讲解 RegisterComponent 的逻辑

  1. 组件定义
    通过 @Component 装饰器定义组件,其中包括选择器、模板和样式。
  2. 表单控件 username, password 以及 passwordconf:

    • username 控件必须有值。
    • password 控件除了必须有值外,还规定了最小长度为 6。
    • passwordconf 仅需要有值即可。
  3. 表单控件 additionalConsents:
    调用了 registerComponentService.generateAdditionalConsentsFormControl 方法,如果这个方法返回了 nullundefined,则使用一个空的 FormArray
  4. 表单提交:
    当用户点击提交按钮时,onSubmit 方法会检查整个表单是否有效。如果表单有效,会在控制台输出表单的数据;如果无效,则会输出错误信息。

完整解析

整个过程通过 FormBuilder 简化了表单创建的过程,而验证逻辑则通过自定义验证器 CustomFormValidators.passwordsMustMatch 实现了密码和确认密码匹配的功能。通过这种方式,可以有效地管理和验证复杂表单。

进一步扩展

对于复杂的表单结构,我们可以继续扩展,比如添加更多的动态表单元素、嵌套表单组等。这些都可以通过 FormBuilder 和自定义验证器来实现,以确保高效管理表单逻辑和保证表单数据的正确性。

总结

Angular 表单功能强大且灵活,通过响应式表单和 FormBuilder 可以方便地管理复杂的表单。本文详细解析了如何创建和验证一个简单的注册表单,通过自定义验证器实现密码匹配,示范了如何在实际项目中使用这些功能。在实际开发中,可以根据需求不断扩展和优化表单逻辑,从而提升用户体验和数据管理效率。


注销
1k 声望1.6k 粉丝

invalid