Refactor ObjectChildTable component to enhance editing functionality
- Removed unused formListName prop and related logic for cleaner code. - Introduced resolveChangeValue function to streamline value handling during edits. - Updated cell rendering to include a new handleCellChange function for better state management. - Simplified the component structure by eliminating unnecessary Form.List integration.
This commit is contained in:
parent
b38af41929
commit
4bd9acdc11
@ -1,6 +1,6 @@
|
||||
import { useMemo, useEffect, useRef } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Table, Skeleton, Card, Button, Flex, Form, Typography } from 'antd'
|
||||
import { Table, Skeleton, Card, Button, Flex, Typography } from 'antd'
|
||||
import PlusIcon from '../../Icons/PlusIcon'
|
||||
import ObjectProperty from './ObjectProperty'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
@ -21,6 +21,14 @@ const getDefaultWidth = (type) => {
|
||||
return DEFAULT_COLUMN_WIDTHS[type] || 200
|
||||
}
|
||||
|
||||
const resolveChangeValue = (val, type) => {
|
||||
if (type === 'bool') return val
|
||||
if (val?.target && typeof val.target === 'object') {
|
||||
return val.target.value
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
const createSkeletonRows = (rowCount, keyPrefix, keyName) => {
|
||||
return Array.from({ length: rowCount }).map((_, index) => {
|
||||
const skeletonKey = `${keyPrefix}-${index}`
|
||||
@ -51,7 +59,6 @@ const ObjectChildTable = ({
|
||||
additionalColumns = [],
|
||||
emptyText = 'No items',
|
||||
isEditing = false,
|
||||
formListName,
|
||||
value = [],
|
||||
rollups = [],
|
||||
onChange,
|
||||
@ -103,34 +110,44 @@ const ObjectChildTable = ({
|
||||
return value ?? []
|
||||
}, [value])
|
||||
|
||||
// When used with antd Form.List, grab the form instance so we can read
|
||||
// the latest row values and pass them into ObjectProperty as objectData.
|
||||
// Assumes this component is rendered within a Form context when editing.
|
||||
const formInstance = Form.useFormInstance()
|
||||
|
||||
const listNamePath = useMemo(() => {
|
||||
if (!formListName) return null
|
||||
return Array.isArray(formListName) ? formListName : [formListName]
|
||||
}, [formListName])
|
||||
|
||||
const tableColumns = useMemo(() => {
|
||||
const propertyColumns = resolvedProperties.map((property) => ({
|
||||
title: property.label || property.name,
|
||||
dataIndex: property.name,
|
||||
key: property.name,
|
||||
width: property.columnWidth || getDefaultWidth(property.type),
|
||||
render: (_text, record) => {
|
||||
render: (_text, record, index) => {
|
||||
if (record?.isSkeleton) {
|
||||
return (
|
||||
<Skeleton.Input active size='small' style={{ width: '100%' }} />
|
||||
)
|
||||
}
|
||||
|
||||
const handleCellChange = (newVal) => {
|
||||
const resolved = resolveChangeValue(newVal, property.type)
|
||||
const currentItems = Array.isArray(itemsSource)
|
||||
? [...itemsSource]
|
||||
: []
|
||||
const updatedItem = {
|
||||
...currentItems[index],
|
||||
[property.name]: resolved
|
||||
}
|
||||
currentItems[index] = updatedItem
|
||||
if (typeof onChange === 'function') {
|
||||
onChange(currentItems)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ObjectProperty
|
||||
{...property}
|
||||
longId={false}
|
||||
objectData={record}
|
||||
isEditing={isEditing}
|
||||
useFormItem={false}
|
||||
name={undefined}
|
||||
value={record[property.name]}
|
||||
onChange={handleCellChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -416,122 +433,6 @@ const ObjectChildTable = ({
|
||||
</Flex>
|
||||
)
|
||||
|
||||
// When editing and a Form.List name is provided, bind rows via Form.List
|
||||
// instead of the manual value/onChange mechanism.
|
||||
if (isEditing === true && formListName) {
|
||||
return (
|
||||
<Form.List name={formListName}>
|
||||
{(fields, { add, remove }) => {
|
||||
const listDataSource = fields.map((field, index) => ({
|
||||
_field: field,
|
||||
_index: index,
|
||||
key: field.key
|
||||
}))
|
||||
const listColumns = resolvedProperties.map((property) => ({
|
||||
title: property.label || property.name,
|
||||
dataIndex: property.name,
|
||||
key: property.name,
|
||||
width: property.columnWidth || getDefaultWidth(property.type),
|
||||
render: (_text, record) => {
|
||||
const field = record?._field
|
||||
if (!field) return null
|
||||
|
||||
// Resolve the most up-to-date row data for this index from the form
|
||||
let rowObjectData = undefined
|
||||
if (formInstance && listNamePath) {
|
||||
const namePath = [...listNamePath, field.name]
|
||||
rowObjectData = formInstance.getFieldValue(namePath)
|
||||
}
|
||||
return (
|
||||
<ObjectProperty
|
||||
{...property}
|
||||
// Bind directly to this list item + property via NamePath
|
||||
name={[field.name, property.name]}
|
||||
longId={false}
|
||||
isEditing={true}
|
||||
objectData={rowObjectData}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}))
|
||||
|
||||
const deleteColumn = {
|
||||
title: '',
|
||||
key: 'delete',
|
||||
width: 10,
|
||||
fixed: 'right',
|
||||
render: (_text, record) => {
|
||||
const field = record?._field
|
||||
const index = record?._index
|
||||
if (!field || index == null) return null
|
||||
return (
|
||||
<Button
|
||||
type='text'
|
||||
danger
|
||||
size='small'
|
||||
icon={<BinIcon />}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
if (typeof remove === 'function') {
|
||||
remove(index)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const listTable = (
|
||||
<Flex vertical>
|
||||
<div ref={mainTableWrapperRef}>
|
||||
<Table
|
||||
dataSource={listDataSource}
|
||||
columns={[...listColumns, ...additionalColumns, deleteColumn]}
|
||||
pagination={false}
|
||||
size={size}
|
||||
loading={loading}
|
||||
rowKey={(record) => record.key ?? record._index}
|
||||
scroll={scrollConfig}
|
||||
locale={{ emptyText }}
|
||||
className={hasRollups ? 'child-table-rollups' : 'child-table'}
|
||||
style={{ maxWidth, minWidth: 0 }}
|
||||
{...tableProps}
|
||||
/>
|
||||
</div>
|
||||
{rollupTable}
|
||||
</Flex>
|
||||
)
|
||||
|
||||
const handleAddListItem = () => {
|
||||
const newItem = {}
|
||||
resolvedProperties.forEach((property) => {
|
||||
if (property?.name) {
|
||||
newItem[property.name] = null
|
||||
}
|
||||
})
|
||||
add(newItem)
|
||||
}
|
||||
|
||||
return (
|
||||
<Card style={{ minWidth: 0 }}>
|
||||
<Flex vertical gap={'middle'}>
|
||||
<Flex justify={'space-between'}>
|
||||
<Button>Actions</Button>
|
||||
<Button
|
||||
type='primary'
|
||||
icon={<PlusIcon />}
|
||||
onClick={handleAddListItem}
|
||||
/>
|
||||
</Flex>
|
||||
{listTable}
|
||||
</Flex>
|
||||
</Card>
|
||||
)
|
||||
}}
|
||||
</Form.List>
|
||||
)
|
||||
}
|
||||
|
||||
if (isEditing === true) {
|
||||
return (
|
||||
<Card>
|
||||
@ -571,7 +472,6 @@ ObjectChildTable.propTypes = {
|
||||
additionalColumns: PropTypes.arrayOf(PropTypes.object),
|
||||
emptyText: PropTypes.node,
|
||||
isEditing: PropTypes.bool,
|
||||
formListName: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
|
||||
value: PropTypes.arrayOf(PropTypes.object),
|
||||
onChange: PropTypes.func,
|
||||
maxWidth: PropTypes.string,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user