动态验证

在很多情况下,您希望根据表单的状态或其他条件来更改验证规则。最常见的例子是,您希望根据用户是第一次提交表单还是非第一次提交,来以不同的方式验证一个字段。

我们通过我们的 onDynamic 验证函数来支持这一点。

vue
<script setup lang="ts">
import { revalidateLogic, useForm } from '@tanstack/vue-form'

// ...

const form = useForm({
  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
    },
  },
})
</script>
<script setup lang="ts">
import { revalidateLogic, useForm } from '@tanstack/vue-form'

// ...

const form = useForm({
  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
    },
  },
})
</script>

默认情况下,onDynamic 不会被调用,所以您需要将 revalidateLogic() 传递给 useFormvalidationLogic 选项。

重新验证选项

revalidateLogic 允许您指定何时运行验证,并根据表单的当前提交状态动态更改验证规则。

它接受两个参数

  • mode: 首次提交表单之前的验证模式。可以是以下任一选项:

    • change: 每次更改时验证。
    • blur: 失去焦点时验证。
    • submit: 提交时验证。(默认
  • modeAfterSubmission: 表单提交后的验证模式。可以是以下任一选项:

    • change: 每次更改时验证。(默认
    • blur: 失去焦点时验证。
    • submit: 提交时验证。

例如,您可以使用以下方式在首次提交后根据失去焦点来重新验证:

vue
<script setup lang="ts">
const form = useForm({
  // ...
  validationLogic: revalidateLogic({
    mode: 'submit',
    modeAfterSubmission: 'blur',
  }),
  // ...
})
</script>
<script setup lang="ts">
const form = useForm({
  // ...
  validationLogic: revalidateLogic({
    mode: 'submit',
    modeAfterSubmission: 'blur',
  }),
  // ...
})
</script>

访问错误

就像您可以访问 onChangeonBlur 验证的错误一样,您也可以使用 form.state.errorMap 对象访问 onDynamic 验证函数中的错误。

vue
<script setup lang="ts">
const form = useForm({
  // ...
  validationLogic: revalidateLogic(),
  validators: {
    onDynamic: ({ value }) => {
      if (!value.firstName) {
        return { firstName: 'A first name is required' }
      }
      return undefined
    },
  },
})
</script>

<template>
  <p>{{ form.state.errorMap.onDynamic?.firstName }}</p>
</template>
<script setup lang="ts">
const form = useForm({
  // ...
  validationLogic: revalidateLogic(),
  validators: {
    onDynamic: ({ value }) => {
      if (!value.firstName) {
        return { firstName: 'A first name is required' }
      }
      return undefined
    },
  },
})
</script>

<template>
  <p>{{ form.state.errorMap.onDynamic?.firstName }}</p>
</template>

与其他验证逻辑结合使用

您可以将 onDynamic 验证与其他的验证逻辑结合使用,例如 onChangeonBlur

vue
<script setup lang="ts">
import { revalidateLogic, useForm } from '@tanstack/vue-form'

const form = useForm({
  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
    },
  },
})
</script>

<template>
  <div>
    <p>{{ form.state.errorMap.onChange?.firstName }}</p>
    <p>{{ form.state.errorMap.onDynamic?.lastName }}</p>
  </div>
</template>
<script setup lang="ts">
import { revalidateLogic, useForm } from '@tanstack/vue-form'

const form = useForm({
  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
    },
  },
})
</script>

<template>
  <div>
    <p>{{ form.state.errorMap.onChange?.firstName }}</p>
    <p>{{ form.state.errorMap.onDynamic?.lastName }}</p>
  </div>
</template>

与字段结合使用

您也可以像使用其他验证逻辑一样,将 onDynamic 验证与字段一起使用。

vue
<script setup lang="ts">
const form = useForm({
  defaultValues: {
    name: '',
    age: 0,
  },
  validationLogic: revalidateLogic(),
  onSubmit({ value }) {
    alert(JSON.stringify(value))
  },
})
</script>

<template>
  <form
    @submit="
      (e) => {
        e.preventDefault()
        e.stopPropagation()
        form.handleSubmit()
      }
    "
  >
    <form.Field
      name="age"
      :validators="{
        onDynamic: ({ value }) =>
          value > 18 ? undefined : 'Age must be greater than 18',
      }"
    >
      <template v-slot="{ field }">
        <div>
          <input
            type="number"
            :value="field.state.value"
            @input="
              (e) =>
                field.handleChange((e.target as HTMLInputElement).valueAsNumber)
            "
            @blur="field.handleBlur"
          />
          <p style="color: red">
            {{ field.state.meta.errorMap.onDynamic }}
          </p>
        </div>
      </template>
    </form.Field>
    <button type="submit">Submit</button>
  </form>
</template>
<script setup lang="ts">
const form = useForm({
  defaultValues: {
    name: '',
    age: 0,
  },
  validationLogic: revalidateLogic(),
  onSubmit({ value }) {
    alert(JSON.stringify(value))
  },
})
</script>

<template>
  <form
    @submit="
      (e) => {
        e.preventDefault()
        e.stopPropagation()
        form.handleSubmit()
      }
    "
  >
    <form.Field
      name="age"
      :validators="{
        onDynamic: ({ value }) =>
          value > 18 ? undefined : 'Age must be greater than 18',
      }"
    >
      <template v-slot="{ field }">
        <div>
          <input
            type="number"
            :value="field.state.value"
            @input="
              (e) =>
                field.handleChange((e.target as HTMLInputElement).valueAsNumber)
            "
            @blur="field.handleBlur"
          />
          <p style="color: red">
            {{ field.state.meta.errorMap.onDynamic }}
          </p>
        </div>
      </template>
    </form.Field>
    <button type="submit">Submit</button>
  </form>
</template>

异步验证

异步验证也可以像其他验证逻辑一样与 onDynamic 一起使用。您甚至可以对异步验证进行防抖处理,以避免过多的调用。

vue
<script setup lang="ts">
const form = useForm({
  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' }
    },
  },
})
</script>
<script setup lang="ts">
const form = useForm({
  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' }
    },
  },
})
</script>

标准模式验证

您还可以使用标准的模式验证库,如 Valibot 或 Zod,结合 onDynamic 验证。这允许您定义复杂的验证规则,这些规则可以根据表单状态动态地改变。

vue
<script setup lang="ts">
import { z } from 'zod'

const schema = z.object({
  firstName: z.string().min(1, 'A first name is required'),
  lastName: z.string().min(1, 'A last name is required'),
})

const form = useForm({
  defaultValues: {
    firstName: '',
    lastName: '',
  },
  validationLogic: revalidateLogic(),
  validators: {
    onDynamic: schema,
  },
})
</script>
<script setup lang="ts">
import { z } from 'zod'

const schema = z.object({
  firstName: z.string().min(1, 'A first name is required'),
  lastName: z.string().min(1, 'A last name is required'),
})

const form = useForm({
  defaultValues: {
    firstName: '',
    lastName: '',
  },
  validationLogic: revalidateLogic(),
  validators: {
    onDynamic: schema,
  },
})
</script>
我们的合作伙伴
Code Rabbit
订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。

订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。