在很多情况下,您希望根据表单的状态或其他条件更改验证规则。最常见的例子是,您希望根据用户是第一次提交表单还是不是,以不同的方式验证一个字段。
我们通过我们的 onDynamic 验证函数来支持这一点。
import { Component } from '@angular/core'
import { TanStackField, injectForm, revalidateLogic } from '@tanstack/angular-form'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<!-- Your form template here -->
`,
})
export class AppComponent {
form = injectForm({
defaultValues: {
firstName: '',
lastName: '',
},
// If this is omitted, onDynamic will not be called
validationLogic: revalidateLogic(),
validators: {
onDynamic: ({ value }) => {
if (!value.firstName) {
return { firstName: 'A first name is required' }
}
return undefined
},
},
})
}
import { Component } from '@angular/core'
import { TanStackField, injectForm, revalidateLogic } from '@tanstack/angular-form'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<!-- Your form template here -->
`,
})
export class AppComponent {
form = injectForm({
defaultValues: {
firstName: '',
lastName: '',
},
// If this is omitted, onDynamic will not be called
validationLogic: revalidateLogic(),
validators: {
onDynamic: ({ value }) => {
if (!value.firstName) {
return { firstName: 'A first name is required' }
}
return undefined
},
},
})
}
默认情况下,不会调用 onDynamic,因此您需要将 revalidateLogic() 传递给 injectForm 的 validationLogic 选项。
revalidateLogic 允许您指定何时运行验证,并根据表单的当前提交状态动态更改验证规则。
它接受两个参数
mode: 首次提交表单之前的验证模式。可以是以下任一选项:
modeAfterSubmission: 表单提交后的验证模式。可以是以下任一选项:
例如,您可以使用以下方式在首次提交后根据失去焦点来重新验证:
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<!-- Your form template here -->
`,
})
export class AppComponent {
form = injectForm({
// ...
validationLogic: revalidateLogic({
mode: 'submit',
modeAfterSubmission: 'blur',
}),
// ...
})
}
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<!-- Your form template here -->
`,
})
export class AppComponent {
form = injectForm({
// ...
validationLogic: revalidateLogic({
mode: 'submit',
modeAfterSubmission: 'blur',
}),
// ...
})
}
就像您可以从 onChange 或 onBlur 验证中访问错误一样,您可以通过 injectStore 访问表单错误映射中 onDynamic 验证函数的错误。
import { Component } from '@angular/core'
import { TanStackField, injectForm, injectStore, revalidateLogic } from '@tanstack/angular-form'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<p>{{ formErrorMap().onDynamic?.firstName }}</p>
`,
})
export class AppComponent {
form = injectForm({
// ...
validationLogic: revalidateLogic(),
validators: {
onDynamic: ({ value }) => {
if (!value.firstName) {
return { firstName: 'A first name is required' }
}
return undefined
},
},
})
formErrorMap = injectStore(this.form, (state) => state.errorMap)
}
import { Component } from '@angular/core'
import { TanStackField, injectForm, injectStore, revalidateLogic } from '@tanstack/angular-form'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<p>{{ formErrorMap().onDynamic?.firstName }}</p>
`,
})
export class AppComponent {
form = injectForm({
// ...
validationLogic: revalidateLogic(),
validators: {
onDynamic: ({ value }) => {
if (!value.firstName) {
return { firstName: 'A first name is required' }
}
return undefined
},
},
})
formErrorMap = injectStore(this.form, (state) => state.errorMap)
}
您可以将 onDynamic 验证与其他验证逻辑一起使用,例如 onChange 或 onBlur。
import { Component } from '@angular/core'
import { TanStackField, injectForm, injectStore, revalidateLogic } from '@tanstack/angular-form'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<div>
<p>{{ formErrorMap().onChange?.firstName }}</p>
<p>{{ formErrorMap().onDynamic?.lastName }}</p>
</div>
`,
})
export class AppComponent {
form = injectForm({
defaultValues: {
firstName: '',
lastName: '',
},
validationLogic: revalidateLogic(),
validators: {
onChange: ({ value }) => {
if (!value.firstName) {
return { firstName: 'A first name is required' }
}
return undefined
},
onDynamic: ({ value }) => {
if (!value.lastName) {
return { lastName: 'A last name is required' }
}
return undefined
},
},
})
formErrorMap = injectStore(this.form, (state) => state.errorMap)
}
import { Component } from '@angular/core'
import { TanStackField, injectForm, injectStore, revalidateLogic } from '@tanstack/angular-form'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<div>
<p>{{ formErrorMap().onChange?.firstName }}</p>
<p>{{ formErrorMap().onDynamic?.lastName }}</p>
</div>
`,
})
export class AppComponent {
form = injectForm({
defaultValues: {
firstName: '',
lastName: '',
},
validationLogic: revalidateLogic(),
validators: {
onChange: ({ value }) => {
if (!value.firstName) {
return { firstName: 'A first name is required' }
}
return undefined
},
onDynamic: ({ value }) => {
if (!value.lastName) {
return { lastName: 'A last name is required' }
}
return undefined
},
},
})
formErrorMap = injectStore(this.form, (state) => state.errorMap)
}
您也可以像使用其他验证逻辑一样,将 onDynamic 验证与字段一起使用。
import { Component } from '@angular/core'
import { TanStackField, injectForm, revalidateLogic } from '@tanstack/angular-form'
import type { FieldValidateFn } from '@tanstack/angular-form'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<form (submit)="handleSubmit($event)">
<ng-container
[tanstackField]="form"
name="age"
[validators]="{
onDynamic: ageValidator
}"
#age="field"
>
<input
type="number"
[value]="age.api.state.value"
(blur)="age.api.handleBlur()"
(input)="age.api.handleChange($any($event).target.valueAsNumber)"
/>
@if (age.api.state.meta.errorMap.onDynamic) {
<p style="color: red">
{{ age.api.state.meta.errorMap.onDynamic }}
</p>
}
</ng-container>
<button type="submit">Submit</button>
</form>
`,
})
export class AppComponent {
ageValidator: FieldValidateFn<any, any, any, any, number> = ({ value }) =>
value > 18 ? undefined : 'Age must be greater than 18'
form = injectForm({
defaultValues: {
name: '',
age: 0,
},
validationLogic: revalidateLogic(),
onSubmit({ value }) {
alert(JSON.stringify(value))
},
})
handleSubmit(event: SubmitEvent) {
event.preventDefault()
event.stopPropagation()
this.form.handleSubmit()
}
}
import { Component } from '@angular/core'
import { TanStackField, injectForm, revalidateLogic } from '@tanstack/angular-form'
import type { FieldValidateFn } from '@tanstack/angular-form'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<form (submit)="handleSubmit($event)">
<ng-container
[tanstackField]="form"
name="age"
[validators]="{
onDynamic: ageValidator
}"
#age="field"
>
<input
type="number"
[value]="age.api.state.value"
(blur)="age.api.handleBlur()"
(input)="age.api.handleChange($any($event).target.valueAsNumber)"
/>
@if (age.api.state.meta.errorMap.onDynamic) {
<p style="color: red">
{{ age.api.state.meta.errorMap.onDynamic }}
</p>
}
</ng-container>
<button type="submit">Submit</button>
</form>
`,
})
export class AppComponent {
ageValidator: FieldValidateFn<any, any, any, any, number> = ({ value }) =>
value > 18 ? undefined : 'Age must be greater than 18'
form = injectForm({
defaultValues: {
name: '',
age: 0,
},
validationLogic: revalidateLogic(),
onSubmit({ value }) {
alert(JSON.stringify(value))
},
})
handleSubmit(event: SubmitEvent) {
event.preventDefault()
event.stopPropagation()
this.form.handleSubmit()
}
}
异步验证也可以像其他验证逻辑一样与 onDynamic 一起使用。您甚至可以对异步验证进行防抖处理,以避免过多的调用。
import { Component } from '@angular/core'
import { TanStackField, injectForm, revalidateLogic } from '@tanstack/angular-form'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<!-- Your form template here -->
`,
})
export class AppComponent {
form = injectForm({
defaultValues: {
username: '',
},
validationLogic: revalidateLogic(),
validators: {
onDynamicAsyncDebounceMs: 500, // Debounce the async validation by 500ms
onDynamicAsync: async ({ value }) => {
if (!value.username) {
return { username: 'Username is required' }
}
// Simulate an async validation
const isValid = await validateUsername(value.username)
return isValid ? undefined : { username: 'Username is already taken' }
},
},
})
}
import { Component } from '@angular/core'
import { TanStackField, injectForm, revalidateLogic } from '@tanstack/angular-form'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<!-- Your form template here -->
`,
})
export class AppComponent {
form = injectForm({
defaultValues: {
username: '',
},
validationLogic: revalidateLogic(),
validators: {
onDynamicAsyncDebounceMs: 500, // Debounce the async validation by 500ms
onDynamicAsync: async ({ value }) => {
if (!value.username) {
return { username: 'Username is required' }
}
// Simulate an async validation
const isValid = await validateUsername(value.username)
return isValid ? undefined : { username: 'Username is already taken' }
},
},
})
}
您还可以将 Valibot 或 Zod 等标准模式验证库与 onDynamic 验证结合使用。这使您可以定义复杂而动态的验证规则,这些规则可以根据表单状态进行更改。
import { Component } from '@angular/core'
import { TanStackField, injectForm, revalidateLogic } from '@tanstack/angular-form'
import { z } from 'zod'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<!-- Your form template here -->
`,
})
export class AppComponent {
schema = z.object({
firstName: z.string().min(1, 'A first name is required'),
lastName: z.string().min(1, 'A last name is required'),
})
form = injectForm({
defaultValues: {
firstName: '',
lastName: '',
},
validationLogic: revalidateLogic(),
validators: {
onDynamic: this.schema,
},
})
}
import { Component } from '@angular/core'
import { TanStackField, injectForm, revalidateLogic } from '@tanstack/angular-form'
import { z } from 'zod'
@Component({
selector: 'app-root',
standalone: true,
imports: [TanStackField],
template: `
<!-- Your form template here -->
`,
})
export class AppComponent {
schema = z.object({
firstName: z.string().min(1, 'A first name is required'),
lastName: z.string().min(1, 'A last name is required'),
})
form = injectForm({
defaultValues: {
firstName: '',
lastName: '',
},
validationLogic: revalidateLogic(),
validators: {
onDynamic: this.schema,
},
})
}
您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。