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 { useMemo, useEffect, useRef } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
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 PlusIcon from '../../Icons/PlusIcon'
|
||||||
import ObjectProperty from './ObjectProperty'
|
import ObjectProperty from './ObjectProperty'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
@ -21,6 +21,14 @@ const getDefaultWidth = (type) => {
|
|||||||
return DEFAULT_COLUMN_WIDTHS[type] || 200
|
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) => {
|
const createSkeletonRows = (rowCount, keyPrefix, keyName) => {
|
||||||
return Array.from({ length: rowCount }).map((_, index) => {
|
return Array.from({ length: rowCount }).map((_, index) => {
|
||||||
const skeletonKey = `${keyPrefix}-${index}`
|
const skeletonKey = `${keyPrefix}-${index}`
|
||||||
@ -51,7 +59,6 @@ const ObjectChildTable = ({
|
|||||||
additionalColumns = [],
|
additionalColumns = [],
|
||||||
emptyText = 'No items',
|
emptyText = 'No items',
|
||||||
isEditing = false,
|
isEditing = false,
|
||||||
formListName,
|
|
||||||
value = [],
|
value = [],
|
||||||
rollups = [],
|
rollups = [],
|
||||||
onChange,
|
onChange,
|
||||||
@ -103,34 +110,44 @@ const ObjectChildTable = ({
|
|||||||
return value ?? []
|
return value ?? []
|
||||||
}, [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 tableColumns = useMemo(() => {
|
||||||
const propertyColumns = resolvedProperties.map((property) => ({
|
const propertyColumns = resolvedProperties.map((property) => ({
|
||||||
title: property.label || property.name,
|
title: property.label || property.name,
|
||||||
dataIndex: property.name,
|
dataIndex: property.name,
|
||||||
key: property.name,
|
key: property.name,
|
||||||
width: property.columnWidth || getDefaultWidth(property.type),
|
width: property.columnWidth || getDefaultWidth(property.type),
|
||||||
render: (_text, record) => {
|
render: (_text, record, index) => {
|
||||||
if (record?.isSkeleton) {
|
if (record?.isSkeleton) {
|
||||||
return (
|
return (
|
||||||
<Skeleton.Input active size='small' style={{ width: '100%' }} />
|
<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 (
|
return (
|
||||||
<ObjectProperty
|
<ObjectProperty
|
||||||
{...property}
|
{...property}
|
||||||
longId={false}
|
longId={false}
|
||||||
objectData={record}
|
objectData={record}
|
||||||
isEditing={isEditing}
|
isEditing={isEditing}
|
||||||
|
useFormItem={false}
|
||||||
|
name={undefined}
|
||||||
|
value={record[property.name]}
|
||||||
|
onChange={handleCellChange}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -416,122 +433,6 @@ const ObjectChildTable = ({
|
|||||||
</Flex>
|
</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) {
|
if (isEditing === true) {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
@ -571,7 +472,6 @@ ObjectChildTable.propTypes = {
|
|||||||
additionalColumns: PropTypes.arrayOf(PropTypes.object),
|
additionalColumns: PropTypes.arrayOf(PropTypes.object),
|
||||||
emptyText: PropTypes.node,
|
emptyText: PropTypes.node,
|
||||||
isEditing: PropTypes.bool,
|
isEditing: PropTypes.bool,
|
||||||
formListName: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
|
|
||||||
value: PropTypes.arrayOf(PropTypes.object),
|
value: PropTypes.arrayOf(PropTypes.object),
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
maxWidth: PropTypes.string,
|
maxWidth: PropTypes.string,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user