Skip to content

表单与验证 ​

使用 useAbpForm 将值、交互状态和验证放在一起。当前表单是平面控制集合,不提供嵌套表单组或动态数组。

提交真实请求 ​

把以下示例放到 src/pages/ProductForm.vue。它假定 POST /api/app/product 接收 { name: string },请替换为自己的端点与 DTO。应用应已按启动指南注册 core 和主题。

vue
<template>
  <form @submit.prevent="save">
    <AbpFormField
      v-slot="{ id, describedBy, invalid }"
      :label="localization.t('AbpIdentity::DisplayName:Name')"
      :errors="messages"
      required
    >
      <AbpInput
        :id="id"
        v-model="form.controls.name.value"
        :aria-describedby="describedBy"
        :invalid="invalid"
        :disabled="saving"
      />
    </AbpFormField>
    <p v-for="message in form.unmatchedServerErrors" :key="message" role="alert">
      {{ message }}
    </p>
    <AbpButton type="submit" :loading="saving">{{ localization.t('AbpUi::Save') }}</AbpButton>
  </form>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue';
import { inject, RestService, useLocalization } from '@lsw-abpvue/core';
import {
  AbpButton,
  AbpFormField,
  AbpInput,
  useAbpForm,
  useServerValidation,
  useValidationMessages,
  Validators,
} from '@lsw-abpvue/theme-shared';

const rest = inject(RestService);
const localization = useLocalization();
const form = useAbpForm({
  name: { value: '', validators: [Validators.required(), Validators.maxLength(128)] },
});
useServerValidation(form);
const validationMessages = useValidationMessages();
const messages = computed(() =>
  form.controls.name.touched ? validationMessages(form.controls.name.errors) : [],
);
const saving = ref(false);

async function save(): Promise<void> {
  if (saving.value || !form.validate()) return;
  saving.value = true;
  try {
    await rest.request<{ name: string }, unknown>({
      method: 'POST',
      url: '/api/app/product',
      body: form.value,
    });
    form.reset();
  } catch {
    // Framework handlers report errors; keep the entered values for correction.
  } finally {
    saving.value = false;
  }
}
</script>

先提交空值,再提交有效名称。处理函数会标记所有字段 touched、验证、防止重复提交,成功后才重置。请求失败保留输入。

值与交互状态 ​

form.controls.name.value 直接是字段值,不需要再取一层 ref。form.value 是当前值对象。不要把原始字段值解构到普通变量后期待它继续响应变化。

操作使用场景
写入 control.value用户编辑,标记 dirty 并移除旧服务端错误
form.patch(values)加载数据,不新增 dirty
form.reset(values)新建编辑基准,清除 touched/dirty/服务端错误
control.markAsTouched()离开字段后显示错误
form.validate()标记全部 touched,并返回提交是否有效
form.clearServerErrors()清除后端错误,不改变字段值

patch 不清除已有 dirty;打开另一条记录时使用 reset。编辑请求需要保留未显示字段、extraProperties 和并发戳。

内置规则 ​

规则示例
必填Validators.required()
长度Validators.minLength(4)、Validators.maxLength(128)
数字范围Validators.min(1)、Validators.max(20)、Validators.range(1, 20)
格式Validators.email()、Validators.url()、Validators.pattern(/\d{4}/)
与其他字段相同Validators.compare('password')

除 required 外,空的可选值会通过其他规则。false 是已定义的布尔值,required 不要求必须勾选。接受条款需要要求 true 的规则。HTML 的范围与长度限制不能替代验证器。后端生成 DTO 可复用生成的规则映射,并显式组合继承规则,它覆盖受支持注解,不覆盖任意业务逻辑。

自定义与条件规则 ​

把以下同步验证器放入 src/forms/registration.ts:

ts
import { useAbpForm, Validators, type AbpValidator } from '@lsw-abpvue/theme-shared';

export const acceptTerms: AbpValidator<boolean> = value =>
  value === true
    ? null
    : {
        rule: 'acceptTerms',
        key: { key: 'BookStore::AcceptTerms', defaultValue: 'Accept the terms before continuing.' },
        params: [],
      };

export const companyWhenBusiness: AbpValidator<string> = (value, context) => {
  if (context.valueOf('business') !== true || value.trim()) return null;
  return {
    rule: 'company',
    key: {
      key: 'BookStore::CompanyRequired',
      defaultValue: 'Company is required for a business account.',
    },
    params: [],
  };
};

export function createRegistrationForm() {
  return useAbpForm({
    business: { value: false },
    company: { value: '', validators: [companyWhenBusiness, Validators.maxLength(128)] },
    accepted: { value: false, validators: [acceptTerms] },
    password: { value: '', validators: [Validators.required(), Validators.minLength(8)] },
    confirmation: { value: '', validators: [Validators.compare('password')] },
  });
}

验证器返回 null 或 { rule, key, params },通过 context.valueOf 读取其他控制。示例只对企业账户要求 Company,并检查两次密码相同。字段显示由页面另外控制,隐藏不会自动取消验证器。

验证器不能返回 Promise。远程唯一性检查应使用独立可取消请求并显示状态,最终仍由后端在保存时保证唯一性。之前查询成功不能代替保存时的校验。

本地化消息 ​

setup 中调用一次 useValidationMessages,再在 computed 中转换错误,使语言切换后文字同步变化。内置验证器的最后一个参数可覆盖消息,支持资源 key 或带后备文字的 key。字段示例展示了 required/email 自定义消息与 touched 后显示策略。

后端验证 ​

请求前在 setup 中调用 useServerValidation(form),把表单连接到框架验证处理。后端成员按不区分大小写及路径末段匹配,因此 Name、ExtraProperties.Name 可对应 name。unmatchedServerErrors 应显示在提交区域,无法匹配字段的错误也必须可见。

框架 HTTP 处理器会报告失败,本地 catch 可以保留表单而不重复显示通用错误。关闭某个请求的全局错误处理后,页面需要自行显示失败。参见HTTP 错误。

在对话框中编辑 ​

打开前加载或重置,给 AbpModal 绑定 form.dirty 和 saving,取消通过 footer 的受保护 close。失败保留对话框,参见模态表单。

分别检查必填、条件、跨字段、后端错误、重复提交、失败保存、重置和语言切换。类型检查通过不等于业务端点已经验证。

非官方社区项目,采用 MIT 许可证,与 Volosoft 无关。