自定義表單驗證器

驗證器的基本概念

在 Angular 中,表單驗證器本質上就是一個函數,它接收一個 AbstractControl 類型的參數(表單控制項),並返回以下結果之一:

  • null 或不返回任何值:表示驗證通過

  • 一個描述錯誤的物件:表示驗證失敗

簡單的自定義驗證器範例

以下是一個檢查輸入值是否包含問號的簡單驗證器:

import { AbstractControl, ValidationErrors } from '@angular/forms';

function mustContainQuestionMark(control: AbstractControl): ValidationErrors | null {
  if (control.value && control.value.includes('?')) {
    return null; // 代表通過這個驗證器
  }
  return { doesNotContainQuestionMark: true };
}

將自定義驗證器添加到表單控制項

將自定義驗證器添加到表單控制項的方法與內建驗證器相同:

password: new FormControl('', {
  validators: [
    Validators.required,
    Validators.minLength(6),
    mustContainQuestionMark,  // 注意:不要加上 () 去執行
  ],
}),

重要提醒:添加驗證器時,只傳遞函數名稱,不要加上 () 去執行。Angular 會在適當的時機自動執行驗證器函數。

在範本中使用自定義驗證器的錯誤訊息

可以像使用內建驗證器的錯誤一樣,檢查自定義驗證器的錯誤:

@if(loginForm.controls.password.touched && loginForm.controls.password.errors?.['doesNotContainQuestionMark']){
  <p class="control-error">Password must contain a question mark (?).</p>
}

或使用 getter 簡化:

get passwordHasNoQuestionMark() {
  const control = this.loginForm.controls.password;
  return control.touched && control.errors?.['doesNotContainQuestionMark'];
}
@if(passwordHasNoQuestionMark){
  <p class="control-error">Password must contain a question mark (?).</p>
}

帶參數的驗證器(驗證器工廠)

有時我們需要創建可配置的驗證器,這時可以使用驗證器工廠模式:

import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';

// 驗證器工廠函數,返回一個驗證器函數
function containsSpecialChar(char: string): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    if (!control.value || control.value.includes(char)) {
      return null; // 驗證通過
    }
    return { missingSpecialChar: { requiredChar: char } };
  };
}

使用方式:

password: new FormControl('', {
  validators: [
    Validators.required,
    Validators.minLength(6),
    containsSpecialChar('?'),  // 現在可以加上 (),因為我們是呼叫工廠函數
  ],
}),

錯誤訊息可以動態顯示:

get passwordSpecialCharError() {
  const control = this.loginForm.controls.password;
  if (control.touched && control.errors?.['missingSpecialChar']) {
    const requiredChar = control.errors['missingSpecialChar'].requiredChar;
    return `Password must contain the special character: ${requiredChar}`;
  }
  return null;
}

小結

自定義驗證器讓我們能夠根據應用需求創建特定的表單驗證邏輯。記住以下幾點:

  1. 驗證器是一個接收 AbstractControl 並返回 ValidationErrors | null 的函數

  2. 驗證通過時返回 null,驗證失敗時返回錯誤物件

  3. 添加驗證器時不要加上 (),除非是調用驗證器工廠函數

  4. 使用驗證器工廠模式可以創建帶參數的可配置驗證器

  5. 非同步驗證器用於需要 API 調用等非同步操作的場景

Last updated