From 3968616fb5ca314ee4c0281d481bc5de885bf488 Mon Sep 17 00:00:00 2001 From: zhanglecong <07akioni2@gmail.com> Date: Mon, 8 Jan 2024 20:55:22 +0800 Subject: [PATCH] fix(form): validation pending --- CHANGELOG.en-US.md | 1 + CHANGELOG.zh-CN.md | 1 + src/form/demos/enUS/index.demo-entry.md | 4 +- src/form/demos/zhCN/index.demo-entry.md | 4 +- src/form/src/Form.tsx | 75 +++++++++++++------------ src/form/src/FormItem.tsx | 18 ++++-- src/form/src/interface.ts | 15 +++-- 7 files changed, 69 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 65c9c7cd4e0..26e90d484b4 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -5,6 +5,7 @@ ### Fixes - Click clear button on components with popup may trigger reopen behaviors. +- Fix `n-form`'s `validate` returned `Promise` may not `resolve`. ### Features diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 4f326ae1ed9..b884c2901bd 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -5,6 +5,7 @@ ### Fixes - 点击具有弹出菜单的组件的清空按钮时,可能会触发菜单的重复出现 +- `n-form` 的 `validate` 方法返回的 `Promise` 可能不会 `resolve` ### Features diff --git a/src/form/demos/enUS/index.demo-entry.md b/src/form/demos/enUS/index.demo-entry.md index 0e463877da9..356ad236f5c 100644 --- a/src/form/demos/enUS/index.demo-entry.md +++ b/src/form/demos/enUS/index.demo-entry.md @@ -104,14 +104,14 @@ Accept all props from FormItem & [GridItem](grid#GridItem-Props) | Name | Type | Description | Version | | --- | --- | --- | --- | -| validate | `(validateCallback?: (errors: Array \| undefined, extra: { warnings: Array \| undefined }) => void, shouldRuleBeApplied?: FormItemRule => boolean) => Promise` | Validate the form. The rejection value type of returned promise is `Array`. | `warnings` `2.37.0` | +| validate | `(validateCallback?: (errors: Array \| undefined, extra: { warnings: Array \| undefined }) => void, shouldRuleBeApplied?: FormItemRule => boolean) => Promise<{ warnings: Array \| undefined }>` | Validate the form. The rejection value type of returned promise is `Array`. | `warnings` `2.37.1` | | restoreValidation | `() => void` | Restore validate. | | ### FormItem, FormItemGi Methods | Name | Type | Description | Version | | --- | --- | --- | --- | -| validate | `(options: { trigger?: string, callback?: (errors: Array \| undefined, extra: { warnings: Array \| undefined }) => void, shouldRuleBeApplied?: FormItemRule => boolean, options?: AsyncValidatorOptions }) => Promise` | Validate the form item. The rejection value type of returned promise is `Array`. If trigger is not set, all rules of the item will be applied. `shouldRuleBeApplied` can filter rules after they are filtered by the trigger. | `warnings` `2.37.0` | +| validate | `(options: { trigger?: string, callback?: (errors: FormValidationError \| undefined, extra: { warnings: FormValidationError \| undefined }) => void, shouldRuleBeApplied?: FormItemRule => boolean, options?: AsyncValidatorOptions }) => Promise<{ warnings: FormValidationError \| undefined }>` | Validate the form item. The rejection value type of returned promise is `FormValidationError`. If trigger is not set, all rules of the item will be applied. `shouldRuleBeApplied` can filter rules after they are filtered by the trigger. | `warnings` `2.37.1` | | restoreValidation | `() => void` | Restore validate. | | To find out more about AsyncValidatorOptions, see async-validator. diff --git a/src/form/demos/zhCN/index.demo-entry.md b/src/form/demos/zhCN/index.demo-entry.md index 06d5d83ffe8..ed9a843b092 100644 --- a/src/form/demos/zhCN/index.demo-entry.md +++ b/src/form/demos/zhCN/index.demo-entry.md @@ -97,14 +97,14 @@ dynamic.vue | 名称 | 类型 | 说明 | 版本 | | --- | --- | --- | --- | -| validate | `(validateCallback?: (errors: Array \| undefined, extra: { warnings: Array \| undefined }) => void, shouldRuleBeApplied?: FormItemRule => boolean) => Promise` | 验证表单,Promise rejection 的返回值类型是 `Array` | `warnings` `2.37.0` | +| validate | `(validateCallback?: (errors: Array \| undefined, extra: { warnings: Array \| undefined }) => void, shouldRuleBeApplied?: FormItemRule => boolean) => Promise<{ warnings: Array \| undefined }>` | 验证表单,Promise rejection 的返回值类型是 `Array` | `warnings` `2.37.1` | | restoreValidation | `() => void` | 还原到未校验的状态 | | ### FormItem, FormItemGi Methods | 名称 | 类型 | 说明 | 版本 | | --- | --- | --- | --- | -| validate | `(options: { trigger?: string, callback?: (errors: Array \| undefined, extra: { warnings: Array \| undefined }) => void, shouldRuleBeApplied?: FormItemRule => boolean, options?: AsyncValidatorOptions }) => Promise` | 验证表项,Promise rejection 的返回值类型是 `Array`。如果不设定 `trigger`,这一个表项全部的规则都会被使用。`shouldRuleBeApplied` 可以用来进一步过滤已经经过 `trigger` 筛选的规则 | `warnings` `2.37.0` | +| validate | `(options: { trigger?: string, callback?: (errors: FormValidationError \| undefined, extra: { warnings: FormValidationError \| undefined }) => void, shouldRuleBeApplied?: FormItemRule => boolean, options?: AsyncValidatorOptions }) => Promise<{ warnings: FormValidationError \| undefined }>` | 验证表项,Promise rejection 的返回值类型是 `FormValidationError`。如果不设定 `trigger`,这一个表项全部的规则都会被使用。`shouldRuleBeApplied` 可以用来进一步过滤已经经过 `trigger` 筛选的规则 | `warnings` `2.37.1` | | restoreValidation | `() => void` | 还原到未校验的状态 | | 关于 AsyncValidatorOptions,参考 async-validator。 diff --git a/src/form/src/Form.tsx b/src/form/src/Form.tsx index 21faf52c813..928b9a09424 100644 --- a/src/form/src/Form.tsx +++ b/src/form/src/Form.tsx @@ -90,44 +90,49 @@ export default defineComponent({ async function validate ( validateCallback?: FormValidateCallback, shouldRuleBeApplied: ShouldRuleBeApplied = () => true - ): Promise { - await new Promise((resolve, reject) => { - const formItemValidationPromises: Array< - Promise - > = [] - for (const key of keysOf(formItems)) { - const formItemInstances = formItems[key] - for (const formItemInstance of formItemInstances) { - if (formItemInstance.path) { - formItemValidationPromises.push( - formItemInstance.internalValidate(null, shouldRuleBeApplied) - ) + ): Promise<{ warnings: ValidateError[][] | undefined }> { + return await new Promise<{ warnings: ValidateError[][] | undefined }>( + (resolve, reject) => { + const formItemValidationPromises: Array< + Promise + > = [] + for (const key of keysOf(formItems)) { + const formItemInstances = formItems[key] + for (const formItemInstance of formItemInstances) { + if (formItemInstance.path) { + formItemValidationPromises.push( + formItemInstance.internalValidate(null, shouldRuleBeApplied) + ) + } } } - } - void Promise.all(formItemValidationPromises).then((results) => { - const formInvalid = results.some((result) => !result.valid) - - const errors = results - .filter((result) => result.errors?.length) - .map((result) => result.errors) - const warnings = results - .filter((result) => result.warnings?.length) - .map((result) => result.warnings) - if (validateCallback) { - validateCallback( - errors?.length ? (errors as ValidateError[][]) : undefined, - { - warnings: warnings?.length - ? (warnings as ValidateError[][]) - : undefined + void Promise.all(formItemValidationPromises).then((results) => { + const formInvalid = results.some((result) => !result.valid) + const errors: ValidateError[][] = [] + const warnings: ValidateError[][] = [] + results.forEach((result) => { + if (result.errors?.length) { + errors.push(result.errors) } - ) - } else { - formInvalid ? reject(errors) : resolve() - } - }) - }) + if (result.warnings?.length) { + warnings.push(result.warnings) + } + }) + if (validateCallback) { + validateCallback(errors.length ? errors : undefined, { + warnings: warnings.length ? warnings : undefined + }) + } + if (formInvalid) { + reject(errors.length ? errors : undefined) + } else { + resolve({ + warnings: warnings.length ? warnings : undefined + }) + } + }) + } + ) } function restoreValidation (): void { for (const key of keysOf(formItems)) { diff --git a/src/form/src/FormItem.tsx b/src/form/src/FormItem.tsx index 98c25c50466..022522a9809 100644 --- a/src/form/src/FormItem.tsx +++ b/src/form/src/FormItem.tsx @@ -209,15 +209,21 @@ export default defineComponent({ } // Resolve : () // Reject : (errors: AsyncValidator.ValidateError[]) - async function validate (options: FormItemValidateOptions): Promise + async function validate (options: FormItemValidateOptions): Promise<{ + warnings: ValidateError[] | undefined + }> async function validate ( trigger?: string | null, callback?: ValidateCallback - ): Promise + ): Promise<{ + warnings: ValidateError[] | undefined + }> async function validate ( options?: string | null | FormItemValidateOptions, callback?: ValidateCallback - ): Promise { + ): Promise<{ + warnings: ValidateError[] | undefined + }> { /** the following code is for compatibility */ let trigger: ValidationTrigger | string | undefined let validateCallback: ValidateCallback | undefined @@ -232,7 +238,9 @@ export default defineComponent({ shouldRuleBeApplied = options.shouldRuleBeApplied asyncValidatorOptions = options.options } - await new Promise((resolve, reject) => { + return await new Promise<{ + warnings: ValidateError[] | undefined + }>((resolve, reject) => { void internalValidate( trigger, shouldRuleBeApplied, @@ -242,7 +250,7 @@ export default defineComponent({ if (validateCallback) { validateCallback(undefined, { warnings }) } - resolve() + resolve({ warnings }) } else { if (validateCallback) { validateCallback(errors, { warnings }) diff --git a/src/form/src/interface.ts b/src/form/src/interface.ts index 1fbbfb1b162..6951bb24337 100644 --- a/src/form/src/interface.ts +++ b/src/form/src/interface.ts @@ -56,10 +56,13 @@ export type FormItemInternalValidate = ( options?: ValidateOption ) => Promise -export type FormItemValidate = (( - options: FormItemValidateOptions -) => Promise) & -((trigger?: string, callback?: ValidateCallback) => Promise) +export type FormItemValidate = ((options: FormItemValidateOptions) => Promise<{ + warnings: ValidateError[] | undefined +}>) & +(( + trigger?: string, + callback?: ValidateCallback +) => Promise<{ warnings: ValidateError[] | undefined }>) export interface FormItemInst { validate: FormItemValidate @@ -100,7 +103,9 @@ export type FormValidateCallback = ( export type FormValidate = ( callback?: FormValidateCallback, shouldRuleBeApplied?: ShouldRuleBeApplied -) => Promise +) => Promise<{ + warnings: ValidateError[][] | undefined +}> export type FormValidationError = ValidateError[]