UNPKG

laravel-precognition-vue

Version:
156 lines (155 loc) 4.89 kB
import { client, createValidator, toSimpleValidationErrors, resolveUrl, resolveMethod, resolveName } from 'laravel-precognition'; import { reactive, ref, toRaw } from 'vue'; import { cloneDeep, get, set } from 'lodash-es'; export { client }; export const useForm = (method, url, inputs, config = {}) => { /** * The original data. */ const originalData = typeof inputs === 'function' ? cloneDeep(inputs()) : cloneDeep(inputs); /** * The original input names. */ const originalInputs = Object.keys(originalData); /** * Reactive valid state. */ const valid = ref([]); /** * Reactive touched state. */ const touched = ref([]); /** * The validator instance. */ const validator = createValidator((client) => client[resolveMethod(method)](resolveUrl(url), form.data(), config), originalData) .on('validatingChanged', () => { form.validating = validator.validating(); }) .on('validatedChanged', () => { valid.value = validator.valid(); }) .on('touchedChanged', () => { touched.value = validator.touched(); }) .on('errorsChanged', () => { form.hasErrors = validator.hasErrors(); // @ts-expect-error form.errors = toSimpleValidationErrors(validator.errors()); valid.value = validator.valid(); }); /** * Resolve the config for a form submission. */ const resolveSubmitConfig = (config) => ({ ...config, precognitive: false, onStart: () => { form.processing = true; (config.onStart ?? (() => null))(); }, onFinish: () => { form.processing = false; (config.onFinish ?? (() => null))(); }, onValidationError: (response, error) => { validator.setErrors(response.data.errors); return config.onValidationError ? config.onValidationError(response) : Promise.reject(error); }, }); /** * Create a new form instance. */ let form = { ...cloneDeep(originalData), data() { const data = cloneDeep(toRaw(form)); return originalInputs.reduce((carry, name) => ({ ...carry, [name]: data[name], }), {}); }, setData(data) { Object.keys(data).forEach((input) => { // @ts-expect-error form[input] = data[input]; }); return form; }, touched(name) { // @ts-expect-error return touched.value.includes(name); }, touch(name) { validator.touch(name); return form; }, validate(name, config) { if (typeof name === 'object' && !('target' in name)) { config = name; name = undefined; } if (typeof name === 'undefined') { validator.validate(config); } else { // @ts-expect-error name = resolveName(name); validator.validate(name, get(form.data(), name), config); } return form; }, validating: false, valid(name) { // @ts-expect-error return valid.value.includes(name); }, invalid(name) { return typeof form.errors[name] !== 'undefined'; }, errors: {}, hasErrors: false, setErrors(errors) { // @ts-expect-error validator.setErrors(errors); return form; }, forgetError(name) { // @ts-expect-error validator.forgetError(name); return form; }, reset(...names) { const original = typeof inputs === 'function' ? cloneDeep(inputs()) : cloneDeep(originalData); if (names.length === 0) { // @ts-expect-error originalInputs.forEach((name) => (form[name] = original[name])); } else { names.forEach((name) => set(form, name, get(original, name))); } // @ts-expect-error validator.reset(...names); return form; }, setValidationTimeout(duration) { validator.setTimeout(duration); return form; }, processing: false, async submit(config = {}) { return client[resolveMethod(method)](resolveUrl(url), form.data(), resolveSubmitConfig(config)); }, validateFiles() { validator.validateFiles(); return form; }, validator() { return validator; }, }; form = reactive(form); return form; };