diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue index 0bb2c70fa..bb5466eff 100644 --- a/src/components/FormModel.vue +++ b/src/components/FormModel.vue @@ -11,6 +11,7 @@ import useNotify from 'src/composables/useNotify.js'; import SkeletonForm from 'components/ui/SkeletonForm.vue'; import VnConfirm from './ui/VnConfirm.vue'; import { tMobile } from 'src/composables/tMobile'; +import { useArrayData } from 'src/composables/useArrayData'; const { push } = useRouter(); const quasar = useQuasar(); @@ -85,28 +86,66 @@ const $props = defineProps({ const emit = defineEmits(['onFetch', 'onDataSaved']); const componentIsRendered = ref(false); +const arrayData = useArrayData($props.model); +const isLoading = ref(false); +// Si elegimos observar los cambios del form significa que inicialmente las actions estaran deshabilitadas +const isResetting = ref(false); +const hasChanges = ref(!$props.observeFormChanges); +const originalData = ref({}); +const formData = computed(() => state.get($props.model)); +const formUrl = computed(() => $props.url); +const defaultButtons = computed(() => ({ + save: { + color: 'primary', + icon: 'save', + label: 'globals.save', + }, + reset: { + color: 'primary', + icon: 'restart_alt', + label: 'globals.reset', + }, + ...$props.defaultButtons, +})); onMounted(async () => { originalData.value = $props.formInitialData; - nextTick(() => { - componentIsRendered.value = true; - }); + + nextTick(() => (componentIsRendered.value = true)); // Podemos enviarle al form la estructura de data inicial sin necesidad de fetchearla state.set($props.model, $props.formInitialData); - if ($props.autoLoad && !$props.formInitialData) { - await fetch(); + if ($props.autoLoad && !$props.formInitialData && $props.url) await fetch(); + else if (arrayData.store.data) { + state.set($props.model, arrayData.store.data); + + emit('onFetch', state.get($props.model)); } - // Si así se desea disparamos el watcher del form después de 100ms, asi darle tiempo de que se haya cargado la data inicial - // para evitar que detecte cambios cuando es data inicial default if ($props.observeFormChanges) { - setTimeout(() => { - startFormWatcher(); - }, 100); + watch( + () => formData.value, + (val) => { + hasChanges.value = !isResetting.value && val; + isResetting.value = false; + }, + { deep: true } + ); } }); +if (!$props.url) + watch( + () => arrayData.store.data, + (val) => updateAndEmit(val, 'onFetch') + ); + +watch(formUrl, async () => { + originalData.value = null; + reset(); + fetch(); +}); + onBeforeRouteLeave((to, from, next) => { if (hasChanges.value && $props.observeFormChanges) quasar.dialog({ @@ -129,49 +168,14 @@ onUnmounted(() => { if ($props.clearStoreOnUnmount) state.unset($props.model); }); -const isLoading = ref(false); -// Si elegimos observar los cambios del form significa que inicialmente las actions estaran deshabilitadas -const isResetting = ref(false); -const hasChanges = ref(!$props.observeFormChanges); -const originalData = ref({}); -const formData = computed(() => state.get($props.model)); -const formUrl = computed(() => $props.url); -const defaultButtons = computed(() => ({ - save: { - color: 'primary', - icon: 'save', - label: 'globals.save', - }, - reset: { - color: 'primary', - icon: 'restart_alt', - label: 'globals.reset', - }, - ...$props.defaultButtons, -})); -const startFormWatcher = () => { - watch( - () => formData.value, - (val) => { - hasChanges.value = !isResetting.value && val; - isResetting.value = false; - }, - { deep: true } - ); -}; - async function fetch() { try { let { data } = await axios.get($props.url, { params: { filter: JSON.stringify($props.filter) }, }); - if (Array.isArray(data)) data = data[0] ?? {}; - state.set($props.model, data); - originalData.value = data && JSON.parse(JSON.stringify(data)); - - emit('onFetch', state.get($props.model)); + updateAndEmit(data, 'onFetch'); } catch (error) { state.set($props.model, {}); originalData.value = {}; @@ -179,31 +183,30 @@ async function fetch() { } async function save() { - if ($props.observeFormChanges && !hasChanges.value) { - notify('globals.noChanges', 'negative'); - return; - } - isLoading.value = true; + if ($props.observeFormChanges && !hasChanges.value) + return notify('globals.noChanges', 'negative'); + isLoading.value = true; try { const body = $props.mapper ? $props.mapper(formData.value) : formData.value; + const method = $props.urlCreate ? 'post' : 'patch'; + const url = + $props.urlCreate || $props.urlUpdate || $props.url || arrayData.store.url; let response; + if ($props.saveFn) response = await $props.saveFn(body); - else - response = await axios[$props.urlCreate ? 'post' : 'patch']( - $props.urlCreate || $props.urlUpdate || $props.url, - body - ); + else response = await axios[method](url, body); + if ($props.urlCreate) notify('globals.dataCreated', 'positive'); - emit('onDataSaved', formData.value, response?.data); - originalData.value = JSON.parse(JSON.stringify(formData.value)); + updateAndEmit(response?.data, 'onDataSaved'); hasChanges.value = false; } catch (err) { console.error(err); notify('errors.writeRequest', 'negative'); + } finally { + isLoading.value = false; } - isLoading.value = false; } async function saveAndGo() { @@ -212,10 +215,7 @@ async function saveAndGo() { } function reset() { - state.set($props.model, originalData.value); - originalData.value = JSON.parse(JSON.stringify(originalData.value)); - - emit('onFetch', state.get($props.model)); + updateAndEmit(originalData.value, 'onFetch'); if ($props.observeFormChanges) { hasChanges.value = false; isResetting.value = true; @@ -237,17 +237,15 @@ function filter(value, update, filterOptions) { ); } -watch(formUrl, async () => { - originalData.value = null; - reset(); - fetch(); -}); +function updateAndEmit(val, evt) { + state.set($props.model, val); + originalData.value = val && JSON.parse(JSON.stringify(val)); + if (!$props.url) arrayData.store.data = val; -defineExpose({ - save, - isLoading, - hasChanges, -}); + emit(evt, state.get($props.model)); +} + +defineExpose({ save, isLoading, hasChanges });