表單需要驗證,才能確保使用者在提交前提供正確、完整的資料。若沒有驗證,你就必須在伺服器上處理資料品質問題、用不清楚的錯誤訊息提供糟糕的使用者體驗,並手動檢查每一個限制條件。
訊號表單提供以結構定義為基礎的驗證方式。驗證規則透過結構定義函式綁定到欄位,在值變更時自動執行,並透過欄位狀態訊號公開錯誤。這實現了反應式驗證,會隨著使用者與表單互動而更新。
驗證基礎
訊號表單的驗證是透過傳給 form() 的第二個引數——結構定義函式——來定義的。
結構定義函式
結構定義函式會收到一個 SchemaPathTree 物件,讓你定義驗證規則:
app.ts
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {Component, signal} from '@angular/core';
import {email, form, FormField, required, submit} from '@angular/forms/signals';
interface LoginData {
email: string;
password: string;
}
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [FormField],
})
export class App {
loginModel = signal<LoginData>({
email: '',
password: '',
});
loginForm = form(this.loginModel, (schemaPath) => {
required(schemaPath.email, {message: 'Email is required'});
email(schemaPath.email, {message: 'Enter a valid email address'});
required(schemaPath.password, {message: 'Password is required'});
});
onSubmit(event: Event) {
event.preventDefault();
submit(this.loginForm, {
action: async () => {
const credentials = this.loginModel();
// In a real app, this would be async:
// await this.authService.login(credentials);
console.log('Logging in with:', credentials);
},
});
}
}
結構定義函式在表單初始化期間執行一次。驗證規則使用結構定義路徑參數(例如 schemaPath.email、schemaPath.password)綁定到欄位,每當欄位值變更時,驗證就會自動執行。
NOTE: 結構定義回呼參數(在這些範例中是 schemaPath)是一個 SchemaPathTree 物件,提供表單中所有欄位的路徑。你可以自由命名這個參數。
驗證的運作方式
訊號表單的驗證遵循以下模式:
- 在結構定義中定義驗證規則:在結構定義函式中將驗證規則綁定到欄位
- 自動執行:欄位值變更時執行驗證規則
- 錯誤傳播:驗證錯誤透過欄位狀態訊號公開
- 反應式更新:驗證狀態變更時,UI 自動更新
互動式欄位每次值變更時都會執行驗證。隱藏、停用與唯讀欄位不會執行驗證——在欄位恢復為互動式之前,它們的驗證規則會被跳過。
驗證時機
驗證規則依以下順序執行:
- 同步驗證:值變更時,所有同步驗證規則都會執行
- 非同步驗證:非同步驗證規則只在所有同步驗證規則都通過後才執行
- 欄位狀態更新:
valid()、invalid()、errors()與pending()訊號隨之更新
同步驗證規則(例如 required()、email())會立即完成。非同步驗證規則(例如 validateHttp())可能需要一些時間,並在執行期間將 pending() 訊號設為 true。
所有驗證規則在每次變更時都會執行——驗證不會在第一個錯誤後短路停止。如果欄位同時有 required() 與 email() 驗證規則,兩者都會執行,而且可以同時產生錯誤。
原生 HTML 驗證
訊號表單不會使用瀏覽器內建的限制驗證來執行驗證規則。這是刻意的設計:訊號表單允許任何元件充當表單控制項,不限於原生表單元素。
取而代之的是,你的驗證規則完全在 Angular 中執行,驗證狀態透過 valid()、invalid() 與 errors() 等欄位狀態訊號公開,而不是透過元素的原生有效性狀態。FormRoot 指令也會在表單元素上設定 novalidate 屬性,使瀏覽器不會阻擋提交。
當欄位綁定到原生表單元素時,某些內建驗證規則會將其限制反映到對應的原生屬性上:required()、min()、max()、minLength() 與 maxLength() 會在元素支援時,設定 required、min、max、minlength 與 maxlength 屬性。例外是 pattern(),它不會設定原生 pattern 屬性。訊號表單設定這些屬性是為了控制輸入行為並改善無障礙體驗,而非觸發原生驗證。
NOTE: 有一種情況訊號表單會讀取原生有效性狀態:當瀏覽器無法剖析原生輸入值時(例如輸入到一半的日期),訊號表單會將其回報為剖析錯誤。即便如此,該錯誤也會像其他驗證錯誤一樣,透過欄位的 errors() 訊號呈現。詳情請參閱值轉換。
IMPORTANT: 不要依賴原生有效性功能,例如 :valid 與 :invalid CSS 虛擬類別、元素的 validity 屬性,或 validationMessage。瀏覽器可能會因為反映的屬性產生副作用,而將某些輸入回報為無效(例如值低於其 min 的數字輸入框),但這種行為會隨驗證規則與輸入類型而異,並不是觀察驗證狀態的受支援方式。
若要根據驗證狀態為控制項設定樣式,請將類別綁定到欄位狀態訊號(請參閱欄位狀態管理),或設定自動狀態類別(請參閱自動狀態類別)。
內建驗證規則
訊號表單為常見的驗證情境提供驗證規則。所有內建驗證規則都接受一個選項物件,用於自訂錯誤訊息與條件邏輯。
required()
required() 驗證規則確保欄位有值:
import {Component, signal} from '@angular/core';
import {form, FormField, required} from '@angular/forms/signals';
@Component({
selector: 'app-registration',
imports: [FormField],
template: `
<form novalidate>
<label>
Username
<input [formField]="registrationForm.username" />
</label>
<label>
Email
<input type="email" [formField]="registrationForm.email" />
</label>
<button type="submit">Register</button>
</form>
`,
})
export class RegistrationComponent {
registrationModel = signal({
username: '',
email: '',
});
registrationForm = form(this.registrationModel, (schemaPath) => {
required(schemaPath.username, {message: 'Username is required'});
required(schemaPath.email, {message: 'Email is required'});
});
}
當欄位的值是下列其中之一時,該欄位被視為「空」;其他所有值都視為非空——包括 0 與空陣列 []:
| 條件 | 範例 |
|---|---|
值為 null |
null |
值為 undefined |
undefined |
| 值為空字串 | '' |
值為 false |
false |
值為 NaN |
NaN |
最後兩項值得特別說明:
false視為空,是為了遵循<input type="checkbox">上required的原生語意,其中未勾選的核取方塊會驗證失敗。NaN視為空,因為它通常是剖析錯誤的結果,並不是有效的數字。
對於條件式必填,請使用 when 選項:
registrationForm = form(this.registrationModel, (schemaPath) => {
required(schemaPath.promoCode, {
message: 'Promo code is required for discounts',
when: ({valueOf}) => valueOf(schemaPath.applyDiscount),
});
});
驗證規則只在 when 函式傳回 true 時執行。
NOTE: required 將空陣列視為有值(有效),因此若要強制陣列項目的最小數量,請使用 minLength()。
email()
email() 驗證規則檢查電子郵件格式是否有效:
import {Component, signal} from '@angular/core';
import {form, FormField, email} from '@angular/forms/signals';
@Component({
selector: 'app-contact',
imports: [FormField],
template: `
<form novalidate>
<label>
Your Email
<input type="email" [formField]="contactForm.email" />
</label>
</form>
`,
})
export class ContactComponent {
contactModel = signal({email: ''});
contactForm = form(this.contactModel, (schemaPath) => {
email(schemaPath.email, {message: 'Please enter a valid email address'});
});
}
email() 驗證規則使用標準的電子郵件格式正規表示式。它接受像 [email protected] 這樣的地址,但會拒絕像 user@ 或 @example.com 這樣格式錯誤的地址。
min() 與 max()
import {Component, signal} from '@angular/core';
import {form, FormField, min, max} from '@angular/forms/signals';
@Component({
selector: 'app-age-form',
imports: [FormField],
template: `
<form novalidate>
<label>
Age
<input type="number" [formField]="ageForm.age" />
</label>
<label>
Rating (1-5)
<input type="number" [formField]="ageForm.rating" />
</label>
</form>
`,
})
export class AgeFormComponent {
ageModel = signal({
age: 0,
rating: 0,
});
ageForm = form(this.ageModel, (schemaPath) => {
min(schemaPath.age, 18, {message: 'You must be at least 18 years old'});
max(schemaPath.age, 120, {message: 'Please enter a valid age'});
min(schemaPath.rating, 1, {message: 'Rating must be at least 1'});
max(schemaPath.rating, 5, {message: 'Rating cannot exceed 5'});
});
}
你可以使用計算值作為動態限制:
ageForm = form(this.ageModel, (schemaPath) => {
min(schemaPath.participants, () => this.minimumRequired(), {
message: 'Not enough participants',
});
});
minDate() 與 maxDate()
minDate() 與 maxDate() 驗證規則處理 Date 值,例如綁定到 <input type="date"> 的欄位。它們也會設定該輸入框的 min 與 max 屬性。
import {Component, signal} from '@angular/core';
import {form, FormField, minDate, maxDate} from '@angular/forms/signals';
@Component({
selector: 'app-booking-form',
imports: [FormField],
template: `
<form novalidate>
<label>
Check-in
<input type="date" [formField]="bookingForm.checkIn" />
</label>
</form>
`,
})
export class BookingFormComponent {
bookingModel = signal<{checkIn: Date | null}>({checkIn: null});
bookingForm = form(this.bookingModel, (schemaPath) => {
minDate(schemaPath.checkIn, new Date('2026-06-01'), {message: 'Bookings open on June 1'});
maxDate(schemaPath.checkIn, new Date('2026-08-31'), {message: 'Bookings close on August 31'});
});
}
IMPORTANT: 無論使用者位於哪個時區,<input type="date"> 讀取與寫入的 Date 值都是 UTC 午夜,因為瀏覽器的 valueAsDate 就是這樣運作的。請以相同方式建立界限,例如使用 new Date('2026-06-01') 或 new Date(Date.UTC(2026, 5, 1))。以本地時間建立的 Date,例如 new Date(2026, 5, 1) 或 new Date(),會被使用者的 UTC 偏移量平移。視時區而定,min 或 max 屬性可能會差一天,界限日期本身也可能被拒絕。
若要要求日期不得早於今天,請使用使用者時區中的今天日期,並以 UTC 午夜表示:
const now = new Date();
const today = new Date(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()));
minDate(schemaPath.checkIn, today, {message: 'Check-in cannot be in the past'});
直接傳入 new Date() 可能會拒絕今天的日期,因為在輸入框中選取的值是 UTC 午夜,早於目前時間。這種情況會發生在 UTC 以及其後的時區。
minLength() 與 maxLength()
minLength() 與 maxLength() 驗證規則處理字串與陣列:
import {Component, signal} from '@angular/core';
import {form, FormField, minLength, maxLength} from '@angular/forms/signals';
@Component({
selector: 'app-password-form',
imports: [FormField],
template: `
<form novalidate>
<label>
Password
<input type="password" [formField]="passwordForm.password" />
</label>
<label>
Bio
<textarea [formField]="passwordForm.bio"></textarea>
</label>
</form>
`,
})
export class PasswordFormComponent {
passwordModel = signal({
password: '',
bio: '',
});
passwordForm = form(this.passwordModel, (schemaPath) => {
minLength(schemaPath.password, 8, {message: 'Password must be at least 8 characters'});
maxLength(schemaPath.password, 100, {message: 'Password is too long'});
maxLength(schemaPath.bio, 500, {message: 'Bio cannot exceed 500 characters'});
});
}
對字串而言,「長度」指的是字元數;對陣列而言,「長度」指的是元素數量。
pattern()
pattern() 驗證規則使用正規表示式進行驗證:
import {Component, signal} from '@angular/core';
import {form, FormField, pattern} from '@angular/forms/signals';
@Component({
selector: 'app-phone-form',
imports: [FormField],
template: `
<form novalidate>
<label>
Phone Number
<input [formField]="phoneForm.phone" placeholder="555-123-4567" />
</label>
<label>
Postal Code
<input [formField]="phoneForm.postalCode" placeholder="12345" />
</label>
</form>
`,
})
export class PhoneFormComponent {
phoneModel = signal({
phone: '',
postalCode: '',
});
phoneForm = form(this.phoneModel, (schemaPath) => {
pattern(schemaPath.phone, /^\d{3}-\d{3}-\d{4}$/, {
message: 'Phone must be in format: 555-123-4567',
});
pattern(schemaPath.postalCode, /^\d{5}$/, {
message: 'Postal code must be 5 digits',
});
});
}
常見的模式:
| 模式類型 | 正規表示式 | 範例 |
|---|---|---|
| 電話 | /^\d{3}-\d{3}-\d{4}$/ |
555-123-4567 |
| 郵遞區號(美國) | /^\d{5}$/ |
12345 |
| 英數字 | /^[a-zA-Z0-9]+$/ |
abc123 |
| URL 安全字元 | /^[a-zA-Z0-9_-]+$/ |
my-url_123 |
陣列項目的驗證
表單可以包含巢狀物件陣列(例如訂單項目清單)。若要對陣列中的每個項目套用驗證規則,請在結構定義函式中使用 applyEach()。applyEach() 會逐一走訪陣列路徑,並為每個項目提供一個路徑,讓你可以像套用在頂層欄位一樣套用驗證器。
import {Component, signal} from '@angular/core';
import {applyEach, FormField, form, min, required, SchemaPathTree} from '@angular/forms/signals';
type Item = {name: string; quantity: number};
interface Order {
title: string;
description: string;
items: Item[];
}
function ItemSchema(item: SchemaPathTree<Item>) {
required(item.name, {message: 'Item name is required'});
min(item.quantity, 1, {message: 'Quantity must be at least 1'});
}
@Component(/* ... */)
export class OrderComponent {
orderModel = signal<Order>({
title: '',
description: '',
items: [{name: '', quantity: 0}],
});
orderForm = form(this.orderModel, (schemaPath) => {
required(schemaPath.title);
required(schemaPath.description);
applyEach(schemaPath.items, ItemSchema);
});
}
驗證錯誤
當驗證規則失敗時,它們會產生描述問題所在的錯誤物件。了解錯誤結構有助於你向使用者提供清楚的回饋。
NOTE: 本節說明驗證規則產生的錯誤。如需在 UI 中顯示與使用驗證錯誤,請參閱欄位狀態管理指南。
錯誤結構
每個驗證錯誤物件都包含以下屬性:
| 屬性 | 說明 |
|---|---|
kind |
失敗的驗證規則(例如 "required"、"email"、"minLength") |
message |
選擇性的人類可讀錯誤訊息 |
內建驗證規則會自動設定 kind 屬性。message 屬性是選擇性的——你可以透過驗證規則選項提供自訂訊息。
自訂錯誤訊息
所有內建驗證規則都接受 message 選項,用於自訂錯誤文字:
import {Component, signal} from '@angular/core';
import {form, FormField, required, minLength} from '@angular/forms/signals';
@Component({
selector: 'app-signup',
imports: [FormField],
template: `
<form novalidate>
<label>
Username
<input [formField]="signupForm.username" />
</label>
<label>
Password
<input type="password" [formField]="signupForm.password" />
</label>
</form>
`,
})
export class SignupComponent {
signupModel = signal({
username: '',
password: '',
});
signupForm = form(this.signupModel, (schemaPath) => {
required(schemaPath.username, {
message: 'Please choose a username',
});
required(schemaPath.password, {
message: 'Password cannot be empty',
});
minLength(schemaPath.password, 12, {
message: 'Password must be at least 12 characters for security',
});
});
}
自訂訊息應清楚、具體,並告訴使用者如何修正問題。不要使用 "Invalid input",而應使用 "Password must be at least 12 characters for security"。
每個欄位的多個錯誤
當欄位有多條驗證規則時,每條驗證規則都會獨立執行,並可能產生一個錯誤:
signupForm = form(this.signupModel, (schemaPath) => {
required(schemaPath.email, {message: 'Email is required'});
email(schemaPath.email, {message: 'Enter a valid email address'});
minLength(schemaPath.email, 5, {message: 'Email is too short'});
});
如果電子郵件欄位是空的,只會出現 required() 錯誤。如果使用者輸入 "a@",email() 與 minLength() 錯誤會同時出現。所有驗證規則都會執行——驗證不會在第一個失敗後停止。
TIP: 在範本中使用 touched() && invalid() 模式,可避免錯誤在使用者與欄位互動之前就出現。如需顯示驗證錯誤的完整指引,請參閱欄位狀態管理指南。
自訂驗證規則
內建驗證規則能處理常見情況,但你經常會需要自訂驗證邏輯,用於業務規則、複雜格式或特定領域的限制。
使用 validate()
validate() 函式用來建立自訂驗證規則。它接收一個驗證器函式,該函式存取欄位上下文並傳回:
| 傳回值 | 意義 |
|---|---|
| 錯誤物件 | 值無效 |
null 或 undefined |
值有效 |
import {Component, signal} from '@angular/core';
import {form, FormField, validate} from '@angular/forms/signals';
@Component({
selector: 'app-url-form',
imports: [FormField],
template: `
<form novalidate>
<label>
Website URL
<input [formField]="urlForm.website" />
</label>
</form>
`,
})
export class UrlFormComponent {
urlModel = signal({website: ''});
urlForm = form(this.urlModel, (schemaPath) => {
validate(schemaPath.website, ({value}) => {
if (!value().startsWith('https://')) {
return {
kind: 'https',
message: 'URL must start with https://',
};
}
return null;
});
});
}
驗證器函式會收到一個 FieldContext 物件,其中包含:
| 屬性 | 型別 | 說明 |
|---|---|---|
value |
Signal | 包含目前欄位值的訊號 |
state |
FieldState | 欄位狀態參照 |
fieldTree |
FieldTree | 欄位樹參照 |
valueOf() |
Method | 依路徑取得另一個欄位的值 |
stateOf() |
Method | 依路徑取得另一個欄位的狀態 |
fieldTreeOf() |
Method | 依路徑取得另一個欄位的欄位樹 |
pathKeys |
Signal | 從根到目前欄位的路徑鍵 |
NOTE: 子欄位也有 key 訊號,陣列項目欄位則同時有 key 與 index 訊號。
驗證失敗時,傳回包含 kind 與 message 的錯誤物件;驗證通過時,傳回 null 或 undefined。
使用 validateTree()
validateTree() 函式用來建立自訂驗證規則,可以鎖定多個欄位,或為整個子樹提供複雜的驗證邏輯。
import {Component, model} from '@angular/core';
import {form, FormField, validateTree} from '@angular/forms/signals';
interface User {
firstName: string;
lastName: string;
}
@Component({/* ... */})
export class UserFormComponent {
readonly userModel = model<User>({
firstName: '',
lastName: '',
});
userForm = form(this.userModel, (path) => {
validateTree(path, (ctx) => {
if (ctx.valueOf(path.firstName).length < 5) {
return {
kind: 'minLength5',
message: 'First name must be at least 5 characters',
fieldTree: ctx.fieldTree.lastName,
};
}
return null;
});
});
}
validateTree() 的驗證器函式會收到與 validate() 相同的 FieldContext 物件。
可重複使用的驗證規則
將 validate() 包裝起來,即可建立可重複使用的驗證規則函式:
function url(path: SchemaPath<string>, options?: {message?: string}) {
validate(path, ({value}) => {
try {
new URL(value());
return null;
} catch {
return {
kind: 'url',
message: options?.message || 'Enter a valid URL',
};
}
});
}
function phoneNumber(path: SchemaPath<string>, options?: {message?: string}) {
validate(path, ({value}) => {
const phoneRegex = /^\d{3}-\d{3}-\d{4}$/;
if (!phoneRegex.test(value())) {
return {
kind: 'phoneNumber',
message: options?.message || 'Phone must be in format: 555-123-4567',
};
}
return null;
});
}
你可以像使用內建驗證規則一樣使用自訂驗證規則:
urlForm = form(this.urlModel, (schemaPath) => {
url(schemaPath.website, {message: 'Please enter a valid website URL'});
phoneNumber(schemaPath.phone);
});
跨欄位驗證
跨欄位驗證會比較或關聯多個欄位的值。
跨欄位驗證的常見情境是密碼確認:
import {Component, signal} from '@angular/core';
import {form, FormField, required, minLength, validate} from '@angular/forms/signals';
@Component({
selector: 'app-password-change',
imports: [FormField],
template: `
<form novalidate>
<label>
New Password
<input type="password" [formField]="passwordForm.password" />
</label>
<label>
Confirm Password
<input type="password" [formField]="passwordForm.confirmPassword" />
</label>
<button type="submit">Change Password</button>
</form>
`,
})
export class PasswordChangeComponent {
passwordModel = signal({
password: '',
confirmPassword: '',
});
passwordForm = form(this.passwordModel, (schemaPath) => {
required(schemaPath.password, {message: 'Password is required'});
minLength(schemaPath.password, 8, {message: 'Password must be at least 8 characters'});
required(schemaPath.confirmPassword, {message: 'Please confirm your password'});
validate(schemaPath.confirmPassword, ({value, valueOf}) => {
const confirmPassword = value();
const password = valueOf(schemaPath.password);
if (confirmPassword !== password) {
return {
kind: 'passwordMismatch',
message: 'Passwords do not match',
};
}
return null;
});
});
}
確認驗證規則使用 valueOf(schemaPath.password) 存取密碼欄位的值,並將它與確認值比較。這條驗證規則會以反應式方式執行——只要任一密碼變更,驗證就會自動重新執行。
條件式驗證
有時驗證規則應該只在特定條件下套用,例如只有在訂單出貨到國外時才驗證送貨地址,或對聯集型別欄位的每個變體套用不同的一組規則。
由於驗證規則位於結構定義函式中,你可以使用組合結構定義的相同結構函式來條件式地套用它們:
- 使用
applyWhen(),根據反應式表單狀態(包括其他欄位的值)啟用一組規則。 - 使用
applyWhenValue(),根據欄位自身的值套用規則。當述詞是型別守衛時,規則的型別會縮小為該值,這使它成為驗證判別聯集與其他變體型別的建議方式。
如需完整範例,包括可重複使用的結構定義與判別聯集,請參閱結構定義與結構定義的可組合性指南。
非同步驗證
非同步驗證處理需要外部資料來源的驗證,例如在伺服器上檢查使用者名稱是否可用,或對照 API 進行驗證。
使用 validateHttp()
validateHttp() 函式執行以 HTTP 為基礎的驗證:
import {Component, signal} from '@angular/core';
import {form, FormField, required, validateHttp} from '@angular/forms/signals';
@Component({
selector: 'app-username-form',
imports: [FormField],
template: `
<form novalidate>
<label>
Username
<input [formField]="usernameForm.username" />
@if (usernameForm.username().pending()) {
<span class="checking">Checking availability...</span>
}
</label>
</form>
`,
})
export class UsernameFormComponent {
usernameModel = signal({username: ''});
usernameForm = form(this.usernameModel, (schemaPath) => {
required(schemaPath.username, {message: 'Username is required'});
validateHttp(schemaPath.username, {
request: ({value}) => `/api/check-username?username=${value()}`,
onSuccess: (response: any) => {
if (response.taken) {
return {
kind: 'usernameTaken',
message: 'Username is already taken',
};
}
return null;
},
onError: (error) => ({
kind: 'networkError',
message: 'Could not verify username availability',
}),
});
});
}
validateHttp() 驗證規則會:
- 呼叫
request函式傳回的 URL 或請求 - 使用
onSuccess將成功回應對應為驗證錯誤或null - 使用
onError處理請求失敗(網路錯誤、HTTP 錯誤) - 在請求進行期間將
pending()設為true - 只在所有同步驗證規則都通過後才執行
待處理狀態
非同步驗證執行期間,欄位的 pending() 訊號會傳回 true。你可以使用它來顯示載入指示器:
@if (form.username().pending()) {
<span class="spinner">Checking...</span>
}
valid() 訊號在驗證待處理期間會傳回 false,即使目前還沒有錯誤。invalid() 訊號則只在存在錯誤時才傳回 true。
與結構定義驗證程式庫整合
訊號表單內建支援符合 Standard Schema 的程式庫,例如 Zod 或 Valibot。這項整合透過 validateStandardSchema 函式提供。它讓你可以使用既有的結構定義,同時保有訊號表單反應式驗證的好處。
import {form, validateStandardSchema} from '@angular/forms/signals';
import {signal} from '@angular/core';
import * as z from 'zod';
// Define your schema
const userSchema = z.object({
email: z.email(),
password: z.string().min(8),
});
// Use with Signal Forms
const userForm = form(signal({email: '', password: ''}), (schemaPath) => {
validateStandardSchema(schemaPath, userSchema);
});
動態結構定義
除了靜態結構定義之外,你也可以傳入一個傳回結構定義的函式。當該函式讀取的訊號變更時,驗證就會自動更新。
import {Component, computed, signal} from '@angular/core';
import {form, FormField, validateStandardSchema} from '@angular/forms/signals';
import * as z from 'zod';
@Component({/* ... */})
export class DynamicSchema {
model = signal({document: '', type: 'dni'});
// Schema reacts automatically to type changes
schema = computed(() =>
z.object({
document:
this.model().type === 'dni'
? z.string().length(8, 'DNI must be 8 digits')
: z.string().min(12, 'Passport must be at least 12 characters'),
}),
);
f = form(this.model, (p) => validateStandardSchema(p, () => this.schema()));
}
後續步驟
本指南介紹了驗證規則的建立與套用。以下是探討訊號表單其他面向的相關指南: