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: {
default: undefined
},
$pcFormField: {
default: undefined
}
},
data() {
@ -52,16 +55,16 @@ export default {
defaultValue(newValue) {
this.d_value = newValue;
},
formControl: {
immediate: true,
handler(newValue) {
this.formField = this.$pcForm?.register?.(this.$formName, newValue) || {};
}
},
$formName: {
immediate: true,
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: {
@ -89,13 +92,16 @@ export default {
return isNotEmpty(this.d_value);
},
$invalid() {
return this.invalid ?? this.$pcForm?.states?.[this.$formName]?.invalid;
return this.invalid ?? this.$pcFormField?.$field?.invalid ?? this.$pcForm?.states?.[this.$formName]?.invalid;
},
$formName() {
return this.formControl?.name || this.name;
return this.name || this.$formControl?.name;
},
$formControl() {
return this.formControl || this.$pcFormField?.formControl;
},
$formDefaultValue() {
return this.d_value ?? this.$pcForm?.initialValues?.[this.$formName];
return this.d_value ?? this.$pcFormField?.initialValue ?? this.$pcForm?.initialValues?.[this.$formName];
},
controlled() {
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 = {}) => {
const states = reactive({});
const fieldOptionMap = reactive({});
const fields = reactive({});
const valid = computed(() => Object.values(states).every((field) => !field.invalid));
const getInitialState = (field) => {
const getInitialState = (field, initialValue) => {
return {
value: options.initialValues?.[field],
value: initialValue ?? options.initialValues?.[field],
touched: false,
dirty: false,
pristine: true,
@ -31,15 +31,29 @@ export const useForm = (options = {}) => {
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) => {
states[field] ||= getInitialState(field);
fieldOptionMap[field] = fieldOptions;
states[field] ||= getInitialState(field, fieldOptions?.initialValue);
const props = mergeProps(resolve(fieldOptions, states[field])?.props, resolve(fieldOptions?.props, states[field]), {
name: field,
onBlur: () => {
states[field].touched = true;
(fieldOptions?.validateOnBlur ?? isFieldValidate(field, options.validateOnBlur)) && validate(field);
validateFieldOn(field, fieldOptions, 'validateOnBlur');
},
onInput: (event) => {
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(
() => states[field].value,
(newValue, oldValue) => {
@ -65,7 +81,7 @@ export const useForm = (options = {}) => {
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) => {
return async (event) => {
let results = undefined;
(options.validateOnSubmit ?? true) && (results = await validate());
const results = await validateOn('validateOnSubmit', true);
return callback({
originalEvent: event,
@ -89,25 +103,34 @@ export const useForm = (options = {}) => {
};
const validate = async (field) => {
const names = Object.keys(states) ?? [];
const values = Object.entries(states).reduce((acc, [key, val]) => {
acc[key] = val.value;
const resolverOptions = Object.entries(states).reduce(
(acc, [key, val]) => {
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)) {
if (sField === field || !field) {
const errors = result.errors?.[sField] ?? [];
//const value = result.values?.[sField] ?? states[sField].value;
result.errors ??= {};
states[sField].invalid = errors.length > 0;
states[sField].valid = !states[sField].invalid;
states[sField].errors = errors;
states[sField].error = errors?.[0] ?? null;
//states[sField].value = value;
for (const [fieldName, fieldInst] of Object.entries(fields)) {
const fieldResolver = fieldInst.options?.resolver;
fieldResolver && (result.errors[fieldName] = await fieldResolver({ value: fieldInst.states.value, name: fieldName })?.errors);
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 = () => {
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 field = Object.keys(fieldOptionMap).find((field) => fieldOptionMap[field]?.validateOnMount);
field && validate(field);
isArray(options.validateOnMount) ? options.validateOnMount.forEach(validate) : validate();
validateOn('validateOnMount');
};
options.validateOnMount && tryOnMounted(validateOnMounted);
tryOnMounted(validateOnMounted);
return {
defineField,
@ -133,6 +153,7 @@ export const useForm = (options = {}) => {
validate,
reset,
valid,
states
states,
fields
};
};