feat: #8217 implement onBeforeSave function for form data processing #1631

Open
jsegarra wants to merge 15 commits from 8217_mapper into dev
6 changed files with 46 additions and 38 deletions

View File

@ -98,6 +98,7 @@ defineExpose({
reset,
hasChanges,
saveChanges,
getChanges,
formData,
originalData,

View File

@ -12,7 +12,7 @@ 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';
import { getDifferences, getUpdatedValues } from 'src/filters';
import { onBeforeSave } from 'src/filters';
const { push } = useRouter();
const quasar = useQuasar();
@ -69,7 +69,7 @@ const $props = defineProps({
},
mapper: {
type: Function,
default: null,
default: onBeforeSave,
},
clearStoreOnUnmount: {
type: Boolean,
@ -111,7 +111,7 @@ 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 = computed(() => state.get(modelValue));
const originalData = computed(() => state.get(modelValue) ?? {});
const formData = ref();
const defaultButtons = computed(() => ({
save: {
@ -221,9 +221,7 @@ async function save() {
isLoading.value = true;
try {
formData.value = trimData(formData.value);
const body = $props.mapper
? $props.mapper(formData.value, originalData.value)
: formData.value;
const body = $props.mapper(originalData.value, formData.value);
const method = $props.urlCreate ? 'post' : 'patch';
const url =
$props.urlCreate || $props.urlUpdate || $props.url || arrayData.store.url;
@ -289,12 +287,7 @@ function trimData(data) {
}
return data;
}
function onBeforeSave(formData, originalData) {
return getUpdatedValues(
Object.keys(getDifferences(formData, originalData)),
formData,
);
}
async function onKeyup(evt) {
if (evt.key === 'Enter' && !('prevent-submit' in attrs)) {
const input = evt.target;
@ -323,6 +316,7 @@ defineExpose({
<template>
<div class="column items-center full-width">
<QForm
id="formModel"
ref="myForm"
v-if="formData"
@submit.prevent
@ -330,8 +324,6 @@ defineExpose({
@reset="reset"
class="q-pa-md"
:style="maxWidth ? 'max-width: ' + maxWidth : ''"
id="formModel"
:mapper="onBeforeSave"
>
<QCard>
<slot

View File

@ -92,30 +92,39 @@ describe('FormModel', () => {
expect(vm.hasChanges).toBe(false);
});
it('should call axios.patch with the right data', async () => {
const spy = vi.spyOn(axios, 'patch').mockResolvedValue({ data: {} });
const { vm } = mount({ propsData: { url, model } });
it('should call axios.post with the right data', async () => {
const spy = vi.spyOn(axios, 'post').mockResolvedValue({ data: {} });
const urlCreate = 'mockUrlCreate';
const { vm } = mount({ propsData: { url, urlCreate, model } });
vm.formData = {};
await vm.$nextTick();
vm.formData = { mockKey: 'newVal' };
const formData = { mockKey: 'newVal', mockKey2: 'newVal2' };
vm.formData = formData;
await vm.$nextTick();
await vm.save();
expect(spy).toHaveBeenCalled();
expect(spy).toHaveBeenCalledWith(urlCreate, formData);
vm.formData.mockKey = 'mockVal';
});
it('should call axios.post with the right data', async () => {
const spy = vi.spyOn(axios, 'post').mockResolvedValue({ data: {} });
it('should call axios.patch with the right data', async () => {
const spy = vi.spyOn(axios, 'patch').mockResolvedValue({ data: {} });
const { vm } = mount({
propsData: { url, model, formInitialData, urlCreate: 'mockUrlCreate' },
propsData: {
url,
model,
formInitialData: { ...formInitialData, key1: 'valueKey1' },
},
});
await vm.$nextTick();
vm.formData.mockKey = 'newVal';
await vm.$nextTick();
await vm.save();
expect(spy).toHaveBeenCalled();
expect(spy).toHaveBeenCalledWith(url, { mockKey: 'newVal' });
vm.formData.mockKey = 'mockVal';
});

View File

@ -1,21 +1,16 @@
export default function getDifferences(obj1, obj2) {
let diff = {};
delete obj1.$index;
delete obj2.$index;
for (let key in obj1) {
if (obj2[key] && JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])) {
diff[key] = obj2[key];
}
}
for (let key in obj2) {
if (
obj1[key] === undefined ||
JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])
) {
diff[key] = obj2[key];
export default function getDifferences(initialData, formData) {
const differences = {};
if (initialData) delete initialData.$index;
if (formData) delete formData.$index;
for (const key in formData) {
if (formData.hasOwnProperty(key)) {
if (!initialData.hasOwnProperty(key) || formData[key] !== initialData[key]) {
if (initialData) {
differences[key] = formData[key];
}
}
}
}
return diff;
return differences;
}

View File

@ -3,6 +3,7 @@ import toDate from './toDate';
import toDateString from './toDateString';
import toDateHourMin from './toDateHourMin';
import toDateHourMinSec from './toDateHourMinSec';
import onBeforeSave from './onBeforeSave';
import toRelativeDate from './toRelativeDate';
import toCurrency from './toCurrency';
import toPercentage from './toPercentage';
@ -19,6 +20,7 @@ import isDialogOpened from './isDialogOpened';
import toCelsius from './toCelsius';
export {
onBeforeSave,
getUpdatedValues,
getDifferences,
isDialogOpened,

View File

@ -0,0 +1,9 @@
import getDifferences from './getDifferences';
import getUpdatedValues from './getUpdatedValues';
export default function onBeforeSave(originalData, formData) {
return getUpdatedValues(
Object.keys(getDifferences(originalData, formData)),
formData,
);
}