Refactor on Form API
parent
859c64c400
commit
daffb1b4f3
|
@ -38,6 +38,9 @@ export default {
|
||||||
},
|
},
|
||||||
$pcForm: {
|
$pcForm: {
|
||||||
default: undefined
|
default: undefined
|
||||||
|
},
|
||||||
|
$pcFormField: {
|
||||||
|
default: undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -52,16 +55,16 @@ export default {
|
||||||
defaultValue(newValue) {
|
defaultValue(newValue) {
|
||||||
this.d_value = newValue;
|
this.d_value = newValue;
|
||||||
},
|
},
|
||||||
formControl: {
|
|
||||||
immediate: true,
|
|
||||||
handler(newValue) {
|
|
||||||
this.formField = this.$pcForm?.register?.(this.$formName, newValue) || {};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
$formName: {
|
$formName: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(newValue) {
|
handler(newValue) {
|
||||||
this.formField = this.$pcForm?.register?.(newValue, this.formControl) || {};
|
this.formField = this.$pcForm?.register?.(newValue, this.$formControl) || {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
$formControl: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newValue) {
|
||||||
|
this.formField = this.$pcForm?.register?.(this.$formName, newValue) || {};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
$formDefaultValue: {
|
$formDefaultValue: {
|
||||||
|
@ -89,13 +92,16 @@ export default {
|
||||||
return isNotEmpty(this.d_value);
|
return isNotEmpty(this.d_value);
|
||||||
},
|
},
|
||||||
$invalid() {
|
$invalid() {
|
||||||
return this.invalid ?? this.$pcForm?.states?.[this.$formName]?.invalid;
|
return this.invalid ?? this.$pcFormField?.$field?.invalid ?? this.$pcForm?.states?.[this.$formName]?.invalid;
|
||||||
},
|
},
|
||||||
$formName() {
|
$formName() {
|
||||||
return this.formControl?.name || this.name;
|
return this.name || this.$formControl?.name;
|
||||||
|
},
|
||||||
|
$formControl() {
|
||||||
|
return this.formControl || this.$pcFormField?.formControl;
|
||||||
},
|
},
|
||||||
$formDefaultValue() {
|
$formDefaultValue() {
|
||||||
return this.d_value ?? this.$pcForm?.initialValues?.[this.$formName];
|
return this.d_value ?? this.$pcFormField?.initialValue ?? this.$pcForm?.initialValues?.[this.$formName];
|
||||||
},
|
},
|
||||||
controlled() {
|
controlled() {
|
||||||
return this.$inProps.hasOwnProperty('modelValue') || (!this.$inProps.hasOwnProperty('modelValue') && !this.$inProps.hasOwnProperty('defaultValue'));
|
return this.$inProps.hasOwnProperty('modelValue') || (!this.$inProps.hasOwnProperty('modelValue') && !this.$inProps.hasOwnProperty('defaultValue'));
|
||||||
|
|
|
@ -9,12 +9,12 @@ function tryOnMounted(fn, sync = true) {
|
||||||
|
|
||||||
export const useForm = (options = {}) => {
|
export const useForm = (options = {}) => {
|
||||||
const states = reactive({});
|
const states = reactive({});
|
||||||
const fieldOptionMap = reactive({});
|
const fields = reactive({});
|
||||||
const valid = computed(() => Object.values(states).every((field) => !field.invalid));
|
const valid = computed(() => Object.values(states).every((field) => !field.invalid));
|
||||||
|
|
||||||
const getInitialState = (field) => {
|
const getInitialState = (field, initialValue) => {
|
||||||
return {
|
return {
|
||||||
value: options.initialValues?.[field],
|
value: initialValue ?? options.initialValues?.[field],
|
||||||
touched: false,
|
touched: false,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
pristine: true,
|
pristine: true,
|
||||||
|
@ -31,15 +31,29 @@ export const useForm = (options = {}) => {
|
||||||
return value === true || (isArray(value) && value.includes(field));
|
return value === true || (isArray(value) && value.includes(field));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const validateOn = async (option, defaultValue) => {
|
||||||
|
let results = {};
|
||||||
|
|
||||||
|
isArray(options[option]) ? options[option].forEach(async (field) => (results = await validate(field))) : (options[option] ?? defaultValue) && (results = await validate());
|
||||||
|
|
||||||
|
const field = Object.keys(fields).find((field) => fields[field]?.options?.[option]);
|
||||||
|
field && (results = await validate(field));
|
||||||
|
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateFieldOn = (field, fieldOptions, option, defaultValue) => {
|
||||||
|
(fieldOptions?.[option] ?? isFieldValidate(field, options[option] ?? defaultValue)) && validate(field);
|
||||||
|
};
|
||||||
|
|
||||||
const defineField = (field, fieldOptions) => {
|
const defineField = (field, fieldOptions) => {
|
||||||
states[field] ||= getInitialState(field);
|
states[field] ||= getInitialState(field, fieldOptions?.initialValue);
|
||||||
fieldOptionMap[field] = fieldOptions;
|
|
||||||
|
|
||||||
const props = mergeProps(resolve(fieldOptions, states[field])?.props, resolve(fieldOptions?.props, states[field]), {
|
const props = mergeProps(resolve(fieldOptions, states[field])?.props, resolve(fieldOptions?.props, states[field]), {
|
||||||
name: field,
|
name: field,
|
||||||
onBlur: () => {
|
onBlur: () => {
|
||||||
states[field].touched = true;
|
states[field].touched = true;
|
||||||
(fieldOptions?.validateOnBlur ?? isFieldValidate(field, options.validateOnBlur)) && validate(field);
|
validateFieldOn(field, fieldOptions, 'validateOnBlur');
|
||||||
},
|
},
|
||||||
onInput: (event) => {
|
onInput: (event) => {
|
||||||
states[field].value = event.hasOwnProperty('value') ? event.value : event.target.value;
|
states[field].value = event.hasOwnProperty('value') ? event.value : event.target.value;
|
||||||
|
@ -54,6 +68,8 @@ export const useForm = (options = {}) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fields[field] = { props, states: states[field], options: fieldOptions };
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => states[field].value,
|
() => states[field].value,
|
||||||
(newValue, oldValue) => {
|
(newValue, oldValue) => {
|
||||||
|
@ -65,7 +81,7 @@ export const useForm = (options = {}) => {
|
||||||
states[field].dirty = true;
|
states[field].dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
(fieldOptions?.validateOnValueUpdate ?? isFieldValidate(field, options.validateOnValueUpdate ?? true)) && validate(field);
|
validateFieldOn(field, fieldOptions, 'validateOnValueUpdate', true);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -74,9 +90,7 @@ export const useForm = (options = {}) => {
|
||||||
|
|
||||||
const handleSubmit = (callback) => {
|
const handleSubmit = (callback) => {
|
||||||
return async (event) => {
|
return async (event) => {
|
||||||
let results = undefined;
|
const results = await validateOn('validateOnSubmit', true);
|
||||||
|
|
||||||
(options.validateOnSubmit ?? true) && (results = await validate());
|
|
||||||
|
|
||||||
return callback({
|
return callback({
|
||||||
originalEvent: event,
|
originalEvent: event,
|
||||||
|
@ -89,25 +103,34 @@ export const useForm = (options = {}) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const validate = async (field) => {
|
const validate = async (field) => {
|
||||||
const names = Object.keys(states) ?? [];
|
const resolverOptions = Object.entries(states).reduce(
|
||||||
const values = Object.entries(states).reduce((acc, [key, val]) => {
|
(acc, [key, val]) => {
|
||||||
acc[key] = val.value;
|
acc.names.push(key);
|
||||||
|
acc.values[key] = val.value;
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
},
|
||||||
|
{ names: [], values: {} }
|
||||||
|
);
|
||||||
|
|
||||||
const result = (await options.resolver?.({ values, names })) ?? {};
|
const result = (await options.resolver?.(resolverOptions)) ?? {};
|
||||||
|
|
||||||
for (const sField of Object.keys(states)) {
|
result.errors ??= {};
|
||||||
if (sField === field || !field) {
|
|
||||||
const errors = result.errors?.[sField] ?? [];
|
|
||||||
//const value = result.values?.[sField] ?? states[sField].value;
|
|
||||||
|
|
||||||
states[sField].invalid = errors.length > 0;
|
for (const [fieldName, fieldInst] of Object.entries(fields)) {
|
||||||
states[sField].valid = !states[sField].invalid;
|
const fieldResolver = fieldInst.options?.resolver;
|
||||||
states[sField].errors = errors;
|
|
||||||
states[sField].error = errors?.[0] ?? null;
|
fieldResolver && (result.errors[fieldName] = await fieldResolver({ value: fieldInst.states.value, name: fieldName })?.errors);
|
||||||
//states[sField].value = value;
|
|
||||||
|
if (fieldName === field || !field) {
|
||||||
|
const errors = result.errors[fieldName] ?? [];
|
||||||
|
//const value = result.values?.[fieldName] ?? states[sField].value;
|
||||||
|
|
||||||
|
states[fieldName].invalid = errors.length > 0;
|
||||||
|
states[fieldName].valid = !states[fieldName].invalid;
|
||||||
|
states[fieldName].errors = errors;
|
||||||
|
states[fieldName].error = errors?.[0] ?? null;
|
||||||
|
//states[fieldName].value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,17 +138,14 @@ export const useForm = (options = {}) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
Object.keys(states).forEach((field) => (states[field] = getInitialState(field)));
|
Object.keys(states).forEach((field) => (fields[field].states = states[field] = getInitialState(field, fields[field]?.options?.initialValue)));
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateOnMounted = () => {
|
const validateOnMounted = () => {
|
||||||
const field = Object.keys(fieldOptionMap).find((field) => fieldOptionMap[field]?.validateOnMount);
|
validateOn('validateOnMount');
|
||||||
|
|
||||||
field && validate(field);
|
|
||||||
isArray(options.validateOnMount) ? options.validateOnMount.forEach(validate) : validate();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
options.validateOnMount && tryOnMounted(validateOnMounted);
|
tryOnMounted(validateOnMounted);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
defineField,
|
defineField,
|
||||||
|
@ -133,6 +153,7 @@ export const useForm = (options = {}) => {
|
||||||
validate,
|
validate,
|
||||||
reset,
|
reset,
|
||||||
valid,
|
valid,
|
||||||
states
|
states,
|
||||||
|
fields
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue