Refactor on Form API

pull/6697/head
Mert Sincan 2024-10-31 13:13:55 +00:00
parent 859c64c400
commit daffb1b4f3
2 changed files with 69 additions and 42 deletions

View File

@ -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'));

View File

@ -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
}; };
}; };