feat: add form onValidate, close #4817
parent
42cc616ed3
commit
a5779f2d18
|
@ -84,6 +84,7 @@ export const formProps = {
|
|||
onFieldsChange: { type: Function as PropType<Callbacks['onFieldsChange']> },
|
||||
onFinish: { type: Function as PropType<Callbacks['onFinish']> },
|
||||
onFinishFailed: { type: Function as PropType<Callbacks['onFinishFailed']> },
|
||||
onValidate: { type: Function as PropType<Callbacks['onValidate']> },
|
||||
};
|
||||
|
||||
export type FormProps = Partial<ExtractPropTypes<typeof formProps>>;
|
||||
|
@ -102,7 +103,7 @@ const Form = defineComponent({
|
|||
}),
|
||||
Item: FormItem,
|
||||
useForm,
|
||||
emits: ['finishFailed', 'submit', 'finish'],
|
||||
emits: ['finishFailed', 'submit', 'finish', 'validate'],
|
||||
setup(props, { emit, slots, expose, attrs }) {
|
||||
const size = useInjectSize(props);
|
||||
const { prefixCls, direction, form: contextForm } = useConfigInject('form', props);
|
||||
|
@ -355,6 +356,9 @@ const Form = defineComponent({
|
|||
rules: computed(() => props.rules),
|
||||
addField,
|
||||
removeField,
|
||||
onValidate: (name, status, errors) => {
|
||||
emit('validate', name, status, errors);
|
||||
},
|
||||
});
|
||||
|
||||
watch(
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
import type { PropType, ExtractPropTypes, ComputedRef } from 'vue';
|
||||
import { watch, defineComponent, computed, nextTick, ref, watchEffect, onBeforeUnmount } from 'vue';
|
||||
import {
|
||||
watch,
|
||||
defineComponent,
|
||||
computed,
|
||||
nextTick,
|
||||
ref,
|
||||
watchEffect,
|
||||
onBeforeUnmount,
|
||||
toRaw,
|
||||
} from 'vue';
|
||||
import cloneDeep from 'lodash-es/cloneDeep';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import Row from '../grid/Row';
|
||||
|
@ -213,6 +222,12 @@ export default defineComponent({
|
|||
validateState.value = res.length ? 'error' : 'success';
|
||||
|
||||
errors.value = res.map(r => r.errors);
|
||||
|
||||
formContext.onValidate(
|
||||
fieldName.value,
|
||||
!errors.value.length,
|
||||
errors.value.length ? toRaw(errors.value[0]) : null,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -19,6 +19,11 @@ export interface FormContextProps {
|
|||
removeField: (eventKey: string) => void;
|
||||
validateTrigger?: ComputedRef<string | string[]>;
|
||||
rules?: ComputedRef<{ [k: string]: ValidationRule[] | ValidationRule }>;
|
||||
onValidate: (
|
||||
name: string | number | string[] | number[],
|
||||
status: boolean,
|
||||
errors: string[] | null,
|
||||
) => void;
|
||||
}
|
||||
|
||||
export const FormContextKey: InjectionKey<FormContextProps> = Symbol('formContextKey');
|
||||
|
@ -38,6 +43,7 @@ export const useInjectForm = () => {
|
|||
model: computed(() => undefined),
|
||||
rules: computed(() => undefined),
|
||||
requiredMark: computed(() => false),
|
||||
onValidate: () => {},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ See more advanced usage at [async-validator](https://github.com/yiminghe/async-v
|
|||
:rules="rules"
|
||||
v-bind="layout"
|
||||
@finish="handleFinish"
|
||||
@validate="handleValidate"
|
||||
@finishFailed="handleFinishFailed"
|
||||
>
|
||||
<a-form-item has-feedback label="Password" name="pass">
|
||||
|
@ -112,6 +113,9 @@ export default defineComponent({
|
|||
const resetForm = () => {
|
||||
formRef.value.resetFields();
|
||||
};
|
||||
const handleValidate = (...args) => {
|
||||
console.log(args);
|
||||
};
|
||||
return {
|
||||
formState,
|
||||
formRef,
|
||||
|
@ -120,6 +124,7 @@ export default defineComponent({
|
|||
handleFinishFailed,
|
||||
handleFinish,
|
||||
resetForm,
|
||||
handleValidate,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -72,7 +72,9 @@ export default defineComponent({
|
|||
},
|
||||
],
|
||||
});
|
||||
const { resetFields, validate, validateInfos } = useForm(modelRef, rulesRef);
|
||||
const { resetFields, validate, validateInfos } = useForm(modelRef, rulesRef, {
|
||||
onValidate: (...args) => console.log(...args),
|
||||
});
|
||||
const onSubmit = () => {
|
||||
validate()
|
||||
.then(() => {
|
||||
|
|
|
@ -49,6 +49,7 @@ A form consists of one or more form fields whose type includes input, textarea,
|
|||
| Events Name | Description | Arguments | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| submit | Defines a function will be called if form data validation is successful. | Function(e:Event) | |
|
||||
| validate | triggers after a form item is validated | Function(name, status, errorMsgs) | | |
|
||||
| finish | Trigger after submitting the form and verifying data successfully | function(values) | - | 2.0.0 |
|
||||
| finishFailed | Trigger after submitting the form and verifying data failed | function({ values, errorFields, outOfDate }) | - | 2.0.0 |
|
||||
|
||||
|
@ -234,5 +235,10 @@ function useForm(
|
|||
) => Promise<RuleError[]>;
|
||||
mergeValidateInfo: (items: ValidateInfo | ValidateInfo[]) => ValidateInfo;
|
||||
clearValidate: (names?: namesType) => void;
|
||||
onValidate?: (
|
||||
name: string | number | string[] | number[],
|
||||
status: boolean,
|
||||
errorMsgs: string[] | null,
|
||||
) => void;
|
||||
};
|
||||
```
|
||||
|
|
|
@ -50,6 +50,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/ORmcdeaoO/Form.svg
|
|||
| 事件名称 | 说明 | 回调参数 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| submit | 数据验证成功后回调事件 | Function(e:Event) | | |
|
||||
| validate | 任一表单项被校验后触发 | Function(name, status, errorMsgs) | |
|
||||
| finish | 提交表单且数据验证成功后回调事件 | function(values) | - | 2.0.0 |
|
||||
| finishFailed | 提交表单且数据验证失败后回调事件 | function({ values, errorFields, outOfDate }) | - | 2.0.0 |
|
||||
|
||||
|
@ -232,5 +233,10 @@ function useForm(
|
|||
) => Promise<RuleError[]>;
|
||||
mergeValidateInfo: (items: ValidateInfo | ValidateInfo[]) => ValidateInfo;
|
||||
clearValidate: (names?: namesType) => void;
|
||||
onValidate?: (
|
||||
name: string | number | string[] | number[],
|
||||
status: boolean,
|
||||
errorMsgs: string[] | null,
|
||||
) => void;
|
||||
};
|
||||
```
|
||||
|
|
|
@ -155,6 +155,11 @@ export interface Callbacks<Values = any> {
|
|||
onFieldsChange?: (changedFields: FieldData[], allFields: FieldData[]) => void;
|
||||
onFinish?: (values: Values) => void;
|
||||
onFinishFailed?: (errorInfo: ValidateErrorEntity<Values>) => void;
|
||||
onValidate?: (
|
||||
name: string | number | string[] | number[],
|
||||
status: boolean,
|
||||
errors: string[] | null,
|
||||
) => void;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { Ref } from 'vue';
|
||||
import { reactive, watch, nextTick, unref, shallowRef } from 'vue';
|
||||
import { reactive, watch, nextTick, unref, shallowRef, toRaw } from 'vue';
|
||||
import cloneDeep from 'lodash-es/cloneDeep';
|
||||
import intersection from 'lodash-es/intersection';
|
||||
import isEqual from 'lodash-es/isEqual';
|
||||
|
@ -8,7 +8,7 @@ import omit from 'lodash-es/omit';
|
|||
import { validateRules } from './utils/validateUtil';
|
||||
import { defaultValidateMessages } from './utils/messages';
|
||||
import { allPromiseFinish } from './utils/asyncUtil';
|
||||
import type { RuleError, ValidateMessages } from './interface';
|
||||
import type { Callbacks, RuleError, ValidateMessages } from './interface';
|
||||
import type { ValidateStatus } from './FormItem';
|
||||
|
||||
interface DebounceSettings {
|
||||
|
@ -98,6 +98,7 @@ function useForm(
|
|||
deep?: boolean;
|
||||
validateOnRuleChange?: boolean;
|
||||
debounce?: DebounceSettings;
|
||||
onValidate?: Callbacks['onValidate'];
|
||||
},
|
||||
): {
|
||||
modelRef: Props | Ref<Props>;
|
||||
|
@ -252,6 +253,11 @@ function useForm(
|
|||
const res = results.filter(result => result && result.errors.length);
|
||||
validateInfos[name].validateStatus = res.length ? 'error' : 'success';
|
||||
validateInfos[name].help = res.length ? res.map(r => r.errors) : '';
|
||||
options?.onValidate?.(
|
||||
name,
|
||||
!res.length,
|
||||
res.length ? toRaw(validateInfos[name].help[0]) : null,
|
||||
);
|
||||
}
|
||||
});
|
||||
return promise;
|
||||
|
|
Loading…
Reference in New Issue