Refactor ComponentPreview and RepeatingTable for Improved Data Handling and Performance
- Updated ComponentPreview.vue to enhance data binding for form fields, ensuring controlled updates to prevent circular reactivity. - Introduced new methods for updating group fields and list items, improving data management and validation. - Enhanced RepeatingTable.vue by replacing the LazyCellValue component with a SimpleCellValue for immediate data display, optimizing rendering performance. - Improved table structure and styling for better user experience, including sticky headers and custom scrollbar styles. - Added logic to initialize repeating tables with default data in form builder, ensuring consistent data handling across components. - Implemented checks to prevent unnecessary updates in form data, enhancing overall application performance.
This commit is contained in:
parent
eab2ca3647
commit
f024cc91dd
@ -184,7 +184,8 @@
|
||||
<template v-for="(field, fieldIndex) in component.props.fields" :key="fieldIndex">
|
||||
<FormKit :type="field.type" :label="field.label" :placeholder="field.placeholder"
|
||||
:name="`${component.props.name}.${groupIndex}.${field.name}`" :options="field.options"
|
||||
v-model="group[field.name]" />
|
||||
:value="group[field.name]"
|
||||
@input="updateGroupField(component.props.name, groupIndex, field.name, $event)" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@ -278,11 +279,12 @@
|
||||
:checked="isItemSelected(component.props.name, index)"
|
||||
@change="toggleItemSelection(component.props.name, index)"
|
||||
class="mr-2 h-4 w-4 rounded border-gray-300" />
|
||||
<input :type="component.props.itemType || 'text'" v-model="safeGetField(component.props.name, previewFormData)[index]"
|
||||
<input :type="component.props.itemType || 'text'"
|
||||
:value="safeGetField(component.props.name, previewFormData)[index]"
|
||||
:placeholder="component.props.placeholder"
|
||||
:class="getItemInputClasses(component.props.name, index, item)"
|
||||
@blur="validateItem(component.props.name, index, item)"
|
||||
@input="handleItemInput(component.props.name, index, $event.target.value)" />
|
||||
@input="updateListItem(component.props.name, index, $event.target.value)" />
|
||||
<div v-if="component.props.enableSorting"
|
||||
class="ml-2 cursor-move text-gray-400 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<Icon name="material-symbols:drag-indicator" class="w-5 h-5" />
|
||||
@ -324,7 +326,7 @@
|
||||
<div v-else-if="component.type === 'repeating-table'" class="repeating-table-wrapper">
|
||||
<RepeatingTable
|
||||
:config="component.props"
|
||||
:model-value="safeGetField(component.props.name, previewFormData) || []"
|
||||
:model-value="getTableData(component.props.name)"
|
||||
:is-preview="isPreview"
|
||||
@update:model-value="updateTableData"
|
||||
/>
|
||||
@ -646,8 +648,10 @@ onMounted(() => {
|
||||
const defaultItems = props.component.props.defaultItems;
|
||||
|
||||
if ((!currentFormData || currentFormData.length === 0) && defaultItems && defaultItems.length > 0) {
|
||||
const updatedData = { ...formStore.previewFormData, [listName]: [...defaultItems] };
|
||||
formStore.updatePreviewFormData(updatedData);
|
||||
nextTick(() => {
|
||||
const updatedData = { ...formStore.previewFormData, [listName]: [...defaultItems] };
|
||||
formStore.updatePreviewFormData(updatedData);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -677,8 +681,10 @@ onMounted(() => {
|
||||
initialGroups.push(newGroup);
|
||||
}
|
||||
|
||||
const updatedData = { ...formStore.previewFormData, [groupName]: initialGroups };
|
||||
formStore.updatePreviewFormData(updatedData);
|
||||
nextTick(() => {
|
||||
const updatedData = { ...formStore.previewFormData, [groupName]: initialGroups };
|
||||
formStore.updatePreviewFormData(updatedData);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -690,11 +696,19 @@ watch(() => props.component.props.defaultItems, (newDefaultItems, oldDefaultItem
|
||||
const listName = props.component.props.name;
|
||||
if (!listName) return;
|
||||
|
||||
// Check if defaultItems actually changed to prevent unnecessary updates
|
||||
const newItemsStr = JSON.stringify(newDefaultItems);
|
||||
const oldItemsStr = JSON.stringify(oldDefaultItems);
|
||||
|
||||
if (newItemsStr === oldItemsStr) return;
|
||||
|
||||
// Always update when defaultItems change, regardless of current form data
|
||||
const items = newDefaultItems || [];
|
||||
|
||||
const updatedData = { ...formStore.previewFormData, [listName]: [...items] };
|
||||
formStore.updatePreviewFormData(updatedData);
|
||||
nextTick(() => {
|
||||
const updatedData = { ...formStore.previewFormData, [listName]: [...items] };
|
||||
formStore.updatePreviewFormData(updatedData);
|
||||
});
|
||||
}
|
||||
}, { deep: true, immediate: true });
|
||||
|
||||
@ -702,7 +716,7 @@ watch(() => props.component.props.defaultItems, (newDefaultItems, oldDefaultItem
|
||||
watch(() => props.component.props.minItems, (newMinItems, oldMinItems) => {
|
||||
if (props.component.type === 'repeating-group') {
|
||||
const groupName = props.component.props.name;
|
||||
if (!groupName) return;
|
||||
if (!groupName || newMinItems === oldMinItems) return;
|
||||
|
||||
const currentGroups = safeGetField(groupName, formStore.previewFormData);
|
||||
const minItems = newMinItems || 1;
|
||||
@ -725,12 +739,51 @@ watch(() => props.component.props.minItems, (newMinItems, oldMinItems) => {
|
||||
updatedGroups.push(newGroup);
|
||||
}
|
||||
|
||||
const updatedData = { ...formStore.previewFormData, [groupName]: updatedGroups };
|
||||
formStore.updatePreviewFormData(updatedData);
|
||||
nextTick(() => {
|
||||
const updatedData = { ...formStore.previewFormData, [groupName]: updatedGroups };
|
||||
formStore.updatePreviewFormData(updatedData);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, { deep: true, immediate: true });
|
||||
|
||||
// Controlled update methods to prevent circular reactivity
|
||||
const updateGroupField = (groupName, groupIndex, fieldName, newValue) => {
|
||||
if (!props.isPreview) return;
|
||||
|
||||
const currentGroups = [...(safeGetField(groupName, formStore.previewFormData) || [])];
|
||||
if (!currentGroups[groupIndex]) return;
|
||||
|
||||
// Only update if value actually changed
|
||||
if (currentGroups[groupIndex][fieldName] === newValue) return;
|
||||
|
||||
currentGroups[groupIndex][fieldName] = newValue;
|
||||
|
||||
nextTick(() => {
|
||||
const updatedData = { ...formStore.previewFormData, [groupName]: currentGroups };
|
||||
formStore.updatePreviewFormData(updatedData);
|
||||
emit('form-data-updated', updatedData);
|
||||
});
|
||||
};
|
||||
|
||||
const updateListItem = (listName, index, newValue) => {
|
||||
if (!props.isPreview) return;
|
||||
|
||||
const currentItems = [...(safeGetField(listName, formStore.previewFormData) || [])];
|
||||
if (currentItems[index] === newValue) return; // No change
|
||||
|
||||
// Validate and handle duplicates
|
||||
if (!checkDuplicates(listName, newValue, index)) return;
|
||||
if (!validateItem(listName, index, newValue)) return;
|
||||
|
||||
currentItems[index] = newValue;
|
||||
|
||||
nextTick(() => {
|
||||
const updatedData = { ...formStore.previewFormData, [listName]: currentItems };
|
||||
formStore.updatePreviewFormData(updatedData);
|
||||
});
|
||||
};
|
||||
|
||||
// Repeating group and dynamic list functionality
|
||||
const addGroupItem = () => {
|
||||
if (!props.isPreview) return;
|
||||
@ -1181,13 +1234,48 @@ const updateListItems = (listName, newItems) => {
|
||||
formStore.updatePreviewFormData(updatedData);
|
||||
};
|
||||
|
||||
// Get table data safely and initialize if needed
|
||||
const getTableData = (tableName) => {
|
||||
if (!tableName) return [];
|
||||
|
||||
// Directly check the form store without using safeGetField to avoid warnings
|
||||
const formData = formStore.previewFormData || {};
|
||||
|
||||
// If field exists and is an array, return it
|
||||
if (formData.hasOwnProperty(tableName) && Array.isArray(formData[tableName])) {
|
||||
return formData[tableName];
|
||||
}
|
||||
|
||||
// If data doesn't exist, initialize it immediately (no nextTick needed for initial render)
|
||||
const initialData = [];
|
||||
const updatedFormData = { ...formData, [tableName]: initialData };
|
||||
formStore.updatePreviewFormData(updatedFormData);
|
||||
|
||||
return initialData;
|
||||
};
|
||||
|
||||
// Update table data for repeating-table component
|
||||
const updateTableData = (newData) => {
|
||||
const tableName = props.component.props.name;
|
||||
if (!tableName) return;
|
||||
|
||||
const updatedFormData = { ...formStore.previewFormData, [tableName]: newData };
|
||||
formStore.updatePreviewFormData(updatedFormData);
|
||||
// Ensure newData is always an array
|
||||
const safeNewData = Array.isArray(newData) ? newData : [];
|
||||
|
||||
// Check if data actually changed to prevent unnecessary updates
|
||||
const currentData = safeGetField(tableName, formStore.previewFormData) || [];
|
||||
const currentDataStr = JSON.stringify(currentData);
|
||||
const newDataStr = JSON.stringify(safeNewData);
|
||||
|
||||
if (currentDataStr === newDataStr) return;
|
||||
|
||||
nextTick(() => {
|
||||
const updatedFormData = { ...formStore.previewFormData, [tableName]: safeNewData };
|
||||
formStore.updatePreviewFormData(updatedFormData);
|
||||
|
||||
// Emit the change for workflow page to sync with its local formData
|
||||
emit('form-data-updated', updatedFormData);
|
||||
});
|
||||
};
|
||||
|
||||
// Form Section Component
|
||||
|
@ -70,9 +70,9 @@
|
||||
</div>
|
||||
|
||||
<div v-if="paginatedData.length > 0" class="table-wrapper">
|
||||
<div class="table-content" ref="tableContainer">
|
||||
<div class="table-container" ref="tableContainer">
|
||||
<table class="data-table">
|
||||
<thead class="table-header-row">
|
||||
<thead class="table-header">
|
||||
<tr>
|
||||
<th v-if="config.showRowNumbers" class="row-number-header">#</th>
|
||||
<th
|
||||
@ -106,7 +106,7 @@
|
||||
:style="{ width: getColumnWidth(column) }"
|
||||
>
|
||||
<div class="cell-content">
|
||||
<LazyCellValue
|
||||
<SimpleCellValue
|
||||
:value="record[column.name]"
|
||||
:column="column"
|
||||
:record="record"
|
||||
@ -298,8 +298,8 @@ import { ref, computed, watch, nextTick, onMounted, onUnmounted } from 'vue'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
|
||||
// Lazy cell component for better performance
|
||||
const LazyCellValue = defineComponent({
|
||||
// Simple cell component that shows data immediately
|
||||
const SimpleCellValue = defineComponent({
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Number, Boolean, Object],
|
||||
@ -315,35 +315,7 @@ const LazyCellValue = defineComponent({
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const isVisible = ref(false)
|
||||
const cellRef = ref(null)
|
||||
|
||||
const observer = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
if (cellRef.value) {
|
||||
observer.value = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
isVisible.value = true
|
||||
observer.value?.disconnect()
|
||||
}
|
||||
})
|
||||
},
|
||||
{ threshold: 0.1 }
|
||||
)
|
||||
observer.value.observe(cellRef.value)
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
observer.value?.disconnect()
|
||||
})
|
||||
|
||||
const formatValue = computed(() => {
|
||||
if (!isVisible.value) return ''
|
||||
|
||||
const value = props.value
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '-'
|
||||
@ -370,13 +342,11 @@ const LazyCellValue = defineComponent({
|
||||
})
|
||||
|
||||
return {
|
||||
isVisible,
|
||||
cellRef,
|
||||
formatValue
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<span ref="cellRef" class="cell-value">
|
||||
<span class="cell-value">
|
||||
{{ formatValue }}
|
||||
</span>
|
||||
`
|
||||
@ -400,7 +370,7 @@ const props = defineProps({
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
// Reactive state
|
||||
const data = ref([...props.modelValue])
|
||||
const data = ref([...(props.modelValue || [])])
|
||||
const searchQuery = ref('')
|
||||
const showModal = ref(false)
|
||||
const showDeleteConfirm = ref(false)
|
||||
@ -487,7 +457,7 @@ const isAddDisabled = computed(() => {
|
||||
})
|
||||
|
||||
const showActions = computed(() => {
|
||||
return (props.config.allowEdit || props.config.allowDelete) && !props.isPreview
|
||||
return props.config.allowEdit || props.config.allowDelete
|
||||
})
|
||||
|
||||
const showRecordCount = computed(() => {
|
||||
@ -543,23 +513,48 @@ const visiblePages = computed(() => {
|
||||
return rangeWithDots.filter((item, index, array) => array.indexOf(item) === index)
|
||||
})
|
||||
|
||||
// Guard to prevent recursive updates
|
||||
const isUpdatingFromProps = ref(false)
|
||||
|
||||
// Watch for external data changes
|
||||
watch(() => props.modelValue, (newValue) => {
|
||||
data.value = [...newValue]
|
||||
// Handle the case where newValue might be undefined/null
|
||||
const safeNewValue = newValue || []
|
||||
|
||||
// Prevent circular updates by checking if data actually changed
|
||||
const newDataStr = JSON.stringify(safeNewValue)
|
||||
const currentDataStr = JSON.stringify(data.value)
|
||||
|
||||
if (newDataStr === currentDataStr) return
|
||||
|
||||
isUpdatingFromProps.value = true
|
||||
data.value = [...safeNewValue]
|
||||
// Clear caches when data changes
|
||||
columnCache.value.clear()
|
||||
recordKeys.value.clear()
|
||||
}, { deep: true })
|
||||
|
||||
nextTick(() => {
|
||||
isUpdatingFromProps.value = false
|
||||
})
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
// Watch for internal data changes and emit
|
||||
watch(data, (newData) => {
|
||||
emit('update:modelValue', [...newData])
|
||||
// Watch for internal data changes and emit (only when not updating from props)
|
||||
watch(data, (newData, oldData) => {
|
||||
if (isUpdatingFromProps.value) return
|
||||
|
||||
// Check if data actually changed
|
||||
const newDataStr = JSON.stringify(newData)
|
||||
const oldDataStr = JSON.stringify(oldData)
|
||||
|
||||
if (newDataStr === oldDataStr) return
|
||||
|
||||
nextTick(() => {
|
||||
emit('update:modelValue', [...newData])
|
||||
})
|
||||
}, { deep: true })
|
||||
|
||||
// Methods
|
||||
const openAddModal = () => {
|
||||
if (props.isPreview) return
|
||||
|
||||
editingIndex.value = null
|
||||
formData.value = {}
|
||||
|
||||
@ -572,8 +567,6 @@ const openAddModal = () => {
|
||||
}
|
||||
|
||||
const openEditModal = (record, index) => {
|
||||
if (props.isPreview) return
|
||||
|
||||
editingIndex.value = index
|
||||
formData.value = { ...record }
|
||||
showModal.value = true
|
||||
@ -606,8 +599,6 @@ const saveRecord = (formData) => {
|
||||
}
|
||||
|
||||
const deleteRecord = (index) => {
|
||||
if (props.isPreview) return
|
||||
|
||||
if (props.config.confirmDelete) {
|
||||
deleteIndex.value = index
|
||||
showDeleteConfirm.value = true
|
||||
@ -693,18 +684,56 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Performance optimizations */
|
||||
.table-content {
|
||||
overflow-x: auto;
|
||||
/* Table Container with Sticky Header */
|
||||
.table-container {
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
max-height: 600px;
|
||||
will-change: transform;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #cbd5e1 #f1f5f9;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.data-table {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Sticky Header */
|
||||
.table-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
background: #f9fafb;
|
||||
border-bottom: 2px solid #e5e7eb;
|
||||
}
|
||||
|
||||
/* Scrollable Body */
|
||||
.table-body {
|
||||
background: white;
|
||||
}
|
||||
|
||||
/* Custom scrollbar for webkit browsers */
|
||||
.table-container::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.table-container::-webkit-scrollbar-track {
|
||||
background: #f1f5f9;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.table-container::-webkit-scrollbar-thumb {
|
||||
background: #cbd5e1;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.table-container::-webkit-scrollbar-thumb:hover {
|
||||
background: #94a3b8;
|
||||
}
|
||||
|
||||
.column-header,
|
||||
@ -875,7 +904,7 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
@apply overflow-x-auto;
|
||||
@apply overflow-hidden w-full;
|
||||
}
|
||||
|
||||
.table-content {
|
||||
@ -894,6 +923,16 @@ onUnmounted(() => {
|
||||
.row-number-header,
|
||||
.actions-header {
|
||||
@apply px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider;
|
||||
background: #f9fafb;
|
||||
border-right: 1px solid #e5e7eb;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
position: relative;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.column-header:last-child,
|
||||
.actions-header {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.row-number-header {
|
||||
@ -932,6 +971,18 @@ onUnmounted(() => {
|
||||
.data-cell,
|
||||
.actions-cell {
|
||||
@apply px-6 py-4 whitespace-nowrap;
|
||||
border-bottom: 1px solid #f3f4f6;
|
||||
border-right: 1px solid #f3f4f6;
|
||||
background: white;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
.data-cell:last-child,
|
||||
.actions-cell {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.row-number {
|
||||
@ -939,11 +990,11 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.cell-content {
|
||||
@apply flex items-center;
|
||||
@apply flex items-center w-full;
|
||||
}
|
||||
|
||||
.cell-value {
|
||||
@apply text-sm text-gray-900;
|
||||
@apply text-sm text-gray-900 w-full;
|
||||
}
|
||||
|
||||
.action-buttons-row {
|
||||
|
@ -2579,6 +2579,10 @@ watchEffect(() => {
|
||||
case 'dynamic-list':
|
||||
newDefaults[component.props.name] = Array.isArray(component.props.defaultItems) ? [...component.props.defaultItems] : [];
|
||||
break;
|
||||
case 'repeating-table':
|
||||
// Initialize repeating table with empty array or default data
|
||||
newDefaults[component.props.name] = Array.isArray(component.props.defaultData) ? [...component.props.defaultData] : [];
|
||||
break;
|
||||
case 'select':
|
||||
case 'radio':
|
||||
if (Array.isArray(component.props.options) && component.props.options.length > 0) {
|
||||
@ -2674,25 +2678,32 @@ const handleFormKitInput = (formData, node) => {
|
||||
console.log('[FormBuilder] FormStore preview data updated to:', JSON.parse(JSON.stringify(formStore.previewFormData)));
|
||||
};
|
||||
|
||||
// Make form data accessible to component previews (for UI rendering, not for triggering script engine)
|
||||
watchEffect(() => {
|
||||
if (formStore) { // Ensure formStore is available
|
||||
formStore.updatePreviewFormData(previewFormData.value);
|
||||
}
|
||||
});
|
||||
|
||||
// Watch for changes in previewFormData to trigger FormScriptEngine
|
||||
// Only update store if data actually changed to prevent recursion
|
||||
watch(() => previewFormData.value, (newData, oldData) => {
|
||||
if (!isPreview.value) return; // Only in preview mode
|
||||
|
||||
// Check if data actually changed to prevent unnecessary updates
|
||||
const newDataStr = JSON.stringify(newData);
|
||||
const oldDataStr = JSON.stringify(oldData);
|
||||
|
||||
if (newDataStr === oldDataStr) {
|
||||
return; // No actual change, skip update
|
||||
}
|
||||
|
||||
console.log('[FormBuilder] previewFormData watcher triggered!');
|
||||
console.log('[FormBuilder] New data:', JSON.parse(JSON.stringify(newData)));
|
||||
console.log('[FormBuilder] Old data:', oldData ? JSON.parse(JSON.stringify(oldData)) : 'undefined');
|
||||
console.log('[FormBuilder] New data:', newDataStr);
|
||||
console.log('[FormBuilder] Old data:', oldDataStr);
|
||||
|
||||
// Update form store
|
||||
formStore.updatePreviewFormData(newData);
|
||||
|
||||
console.log('[FormBuilder] FormStore preview data updated to:', JSON.parse(JSON.stringify(formStore.previewFormData)));
|
||||
// Use nextTick to avoid synchronous updates that can cause recursion
|
||||
nextTick(() => {
|
||||
// Only update store if the data is still different (hasn't been changed by something else)
|
||||
const currentDataStr = JSON.stringify(previewFormData.value);
|
||||
if (currentDataStr === newDataStr) {
|
||||
formStore.updatePreviewFormData(newData);
|
||||
console.log('[FormBuilder] FormStore preview data updated to:', JSON.parse(JSON.stringify(formStore.previewFormData)));
|
||||
}
|
||||
});
|
||||
}, { deep: true, immediate: false });
|
||||
|
||||
const navigateToManage = () => {
|
||||
|
@ -1214,7 +1214,7 @@ watch(currentStep, async (newStep) => {
|
||||
if (currentForm.value?.formComponents) {
|
||||
formStore.formComponents = currentForm.value.formComponents;
|
||||
|
||||
// Initialize repeating groups in form data
|
||||
// Initialize repeating groups and tables in form data
|
||||
const updatedFormData = { ...formData.value };
|
||||
currentForm.value.formComponents.forEach(component => {
|
||||
if (component.type === 'repeating-group' && component.props?.name) {
|
||||
@ -1240,6 +1240,13 @@ watch(currentStep, async (newStep) => {
|
||||
|
||||
updatedFormData[groupName] = initialGroups;
|
||||
}
|
||||
} else if (component.type === 'repeating-table' && component.props?.name) {
|
||||
const tableName = component.props.name;
|
||||
|
||||
// If the field doesn't exist or is not an array, initialize it as empty array
|
||||
if (!updatedFormData[tableName] || !Array.isArray(updatedFormData[tableName])) {
|
||||
updatedFormData[tableName] = component.props.defaultData ? [...component.props.defaultData] : [];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user