Table component of Antd nests Table and selector box linkage operation
- 2021-09-04 23:26:51
- OfStack
1. Requirements
When using Table component to nest Table, the selection boxes of father and son Table need to be linked, that is, the parent Table needs to be selected, all the children Table under the row need to be selected, and all the children Table are selected, so the one row of the parent Table where the child Table is located also needs to be selected.
2. rowSelection Configuration for Table
If father and son Table are linked, OnChange cannot be used, but OnSelect and OnSelectAll need to be configured manually.
selectedRowKeys: Specifies an key array of selected items
OnSelect: Manually select/deselect callbacks for a row
OnSelect (record, selected, selectedRows)
record: Selected current row data
selected: Checked, true: Checked, false: Unchecked
selectedRows: Selected array
OnSelectAll: Manually select/deselect callbacks for all rows
OnSelect (selected, selectedRows, changeRows)
selected: Checked, true: Checked, false: Unchecked
selectedRows: Selected array
changeRows: All arrays changed
3. Build Table nested Table interface according to antd document
import React, { useEffect, useState } from 'react';
import { Table, } from 'antd'
export default () => {
const dataSource: any = [
{
key: '1',
title: ' Restaurant Hotel / Waiter ',
number: '8 Home stores, a total 8 People ',
time: '2020.05.25 15:35',
childData: [
{
key: '1.1',
jobTitle: ' Bucket foot bath - Security guard ',
num: '2 People ',
},
{
key: '1.2',
jobTitle: ' Bucket foot bath - Security guard ',
num: '5 People ',
},
]
},
{
key: '2',
title: ' Restaurant Hotel / Cashier ',
number: ' No stores, total 5 People ',
time: '2020.06.06 11:35',
childData: [
{
key: '2.1',
jobTitle: ' Bucket foot bath ',
num: '0 People ',
},
{
key: '2.2',
jobTitle: ' Bucket foot bath ',
num: '1 People ',
},
]
},
]
const parentColumns: any = [
{
title: ' Type of work ',
dataIndex: 'title',
key: 'title',
},
{
title: ' Number of associated stores ',
dataIndex: 'number',
key: 'number',
},
{
title: ' Time ',
dataIndex: 'time',
key: 'time',
},
]
const expandedRowRender = (record: any, index: any, indent: any, expanded: any) => {
const childData = record.childData
const childColumns: any = [
{
title: ' Job title ',
dataIndex: 'jobTitle',
key: 'jobTitle'
},
{
title: ' Number of recruits ',
dataIndex: 'num',
key: 'num'
},
]
return <Table columns={childColumns} dataSource={childData} pagination={false} rowSelection={childRowSelection} />
}
return (
<div>
<Table columns={parentColumns} dataSource={dataSource} expandable={{ expandedRowRender }} rowSelection={parentRowSelection} />
</div>
);
}
4. Start configuring rowSelection
1. Configure rowSelection of parent and child Table
const childRowSelection = {
selectedRowKeys: childSelectedRowKeys,
onSelect: onChildSelectChange,
onSelectAll: onChildSelectAll
}
const parentRowSelection = {
selectedRowKeys: parentSelectedRowKeys,
onSelect: onParentSelectChange,
onSelectAll: onParentSelectAll,
}
2. Create childSelectedRowKeys and parentSelectedRowKeys variables to store the selected key value of parent and child Table
const [parentSelectedRowKeys, setParentSelectedRowKeys] = useState < any > ([])
const [childSelectedRowKeys, setChildSelectedRowKeys] = useState < any > ([])
3. Set child Table to manually select/cancel the callback onChildSelectChange of a line
When single is selected, the current row is selected. If all the options of the Table are selected, the row of the parent Table corresponding to the child Table is also selected
const onChildSelectChange = (record: any, selected: any, selectedRows: any) => {
let childArr: any = [...childSelectedRowKeys];
// No. 1 1 Step Judge selected true Select to set the key Value is added to the childArr , false Unchecked, sets the key Value from childArr Remove from
if (selected) {
childArr.push(record.key)
} else {
childArr.splice(childArr.findIndex((item: any) => item === record.key), 1)
}
// Must be removed undefined Otherwise selectedRows Will put other children Table Selected in the key Value is placed in the array, but the value is undefined , such as: [ undefined , 1 , uundefined]
selectedRows = selectedRows.filter((a: any) => a !== undefined)
// No. 1 2 Step, judge selectedRows Is the length of data Medium child If the length of the parent is equal, the parent table Select, do not select until you wait
for (let item of dataSource) {
if (item.childData.find((d: any) => d.key === record.key)) {
let parentArr: any = [...parentSelectedRowKeys];
if (item.childData.length === selectedRows.length) {
parentArr.push(item.key)
} else {
if (parentArr.length && parentArr.find((d: any) => d === item.key)) {
parentArr.splice(parentArr.findIndex((item1: any) => item1 === item.key), 1)
}
}
setParentSelectedRowKeys(parentArr)
break;
}
}
setChildSelectedRowKeys(childArr)
}
4. Set child Table to manually select/deselect callback onChildSelectAll for all rows
When Select All is selected, all children ES 117EN are selected, and the parent ES 119EN row corresponding to the child ES 118EN is also selected. When Select All is unselected, all children ES 120EN are unselected, and the parent ES 121EN row is also unselected
const onChildSelectAll = (selected: any, selectedRows: any, changeRows: any) => {
// No. 1 1 Step: Judge selected , true : Will son Table Select all, false : Will son Table Uncheck All
let childArr: any = [...childSelectedRowKeys];
if (selected) {
// All selection
childArr = Array.from(new Set([...childArr, ...changeRows.map((item: any) => item.key)]))
} else {
// Cancel all selection
childArr = childArr.filter((item: any) => !changeRows.some((e: any) => e.key === item))
}
// No. 1 2 Step: Find the child Table Corresponding parent Table In the line, and then judge selected , true : Parent Table Select the row in which, false : Parent Table The row in which it is located is unchecked
for (let item of dataSource) {
if (item.childData.find((d: any) => d.key === changeRows[0].key)) {
let parentArr: any = [...parentSelectedRowKeys];
if (selected) {
// All selection
parentArr.push(item.key)
} else {
// Cancel all selection
parentArr.splice(parentArr.findIndex((item: any) => item === item.key), 1)
}
setParentSelectedRowKeys(parentArr)
break;
}
}
setChildSelectedRowKeys(childArr)
}
5. Set the parent Table to manually select/cancel the callback onParentSelctChange of a line
When one row of parent Table is selected, all the children Table under the row are selected. When deselecting, all the children Table under the row are also unselected
const onParentSelectChange = (record: any, selected: any, selectedRows: any) => {
let patentArr: any = [...parentSelectedRowKeys];
let childArr: any = [...childSelectedRowKeys];
//setChildArr : Select the parent Table All sub-options under
let setChildArr = dataSource.find((d: any) => d.key === record.key).childData.map((item: any) => item.key)
// No. 1 1 Step Judge selected true : Select, false , uncheck
if (selected) {
// No. 1 2 Step, father Table Select, child Table Select all (integrate all into 1 Get up and then go heavy)
patentArr.push(record.key)
childArr = Array.from(new Set([...setChildArr, ...childArr]))
} else {
// No. 1 2 Step, father Table Uncheck, child Table Uncheck all (for childArr Filter out the unchecked parent Table All children under Table Adj. key )
patentArr.splice(patentArr.findIndex((item: any) => item === record.key), 1)
childArr = childArr.filter((item: any) => !setChildArr.some((e: any) => e === item))
}
// No. 1 3 Step to set the parent's and child's SelectedRowKeys
setParentSelectedRowKeys(patentArr)
setChildSelectedRowKeys(childArr)
}
6. Set parent Table to manually select/deselect callback onParentSelectAll for all rows
When all are selected, all parent Table and all corresponding children Table are selected. When all selections are unchecked, the parent Table is unchecked and all child Table are unchecked
const onParentSelectAll = (selected: any, selectedRows: any, changeRows: any) => {
let patentArr: any = [...parentSelectedRowKeys];
let setChildArr: any = [];
// The father who will change Table Lower son Table Under key Add to setChildArr Medium
changeRows.forEach((e: any) => {
setChildArr = [...setChildArr, ...e.childData.map((item: any) => item.key)]
});
// No. 1 1 Step judgment selected true : All choices, false : Cancel all selections
if (selected) {
// No. 1 2 Step: Parent Table Select, child Table Select all, set sub Table Adj. SelectedRowKeys
patentArr = Array.from(new Set([...patentArr, ...changeRows.map((item: any) => item.key)]))
setChildSelectedRowKeys(setChildArr)
} else {
// No. 1 2 Step: Parent Table Uncheck, child Table Uncheck all, set child Table Adj. SelectedRowKeys
patentArr = patentArr.filter((item: any) => !changeRows.some((e: any) => e.key === item))
setChildSelectedRowKeys([])
}
// No. 1 3 Step: Set the parent Table Adj. SelectedRowKeys
setParentSelectedRowKeys(patentArr)
}
In this way, the selection box linkage between father and son Table is completed,
Note: The dataSource data format depends on its own format
5. Complete Demo
Table nested Table complete code
import React, { useEffect, useState } from 'react';
import { Table, Button } from 'antd'
import { PlusOutlined } from '@ant-design/icons';
export default () => {
const [parentSelectedRowKeys, setParentSelectedRowKeys] = useState<any>([])
const [childSelectedRowKeys, setChildSelectedRowKeys] = useState<any>([])
console.log(parentSelectedRowKeys, 'parentSelectedRowKeys')
console.log(childSelectedRowKeys, 'childSelectedRowKeys')
const dataSource: any = [
{
key: '1',
title: '餐饮酒店/服务员',
number: '8家门店,共8人',
time: '2020.05.25 15:35',
childData: [
{
key: '1.1',
jobTitle: '大桶大足浴-保安',
num: '2人',
},
{
key: '1.2',
jobTitle: '大桶大足浴-保安',
num: '5人',
},
]
},
{
key: '2',
title: '餐饮酒店/收银员',
number: '无门店,共5人',
time: '2020.06.06 11:35',
childData: [
{
key: '2.1',
jobTitle: '大桶大足浴',
num: '0人',
},
{
key: '2.2',
jobTitle: '大桶大足浴',
num: '1人',
},
]
},
]
const parentColumns: any = [
{
title: '工种',
dataIndex: 'title',
key: 'title',
},
{
title: '关联门店数',
dataIndex: 'number',
key: 'number',
},
{
title: '时间',
dataIndex: 'time',
key: 'time',
},
]
const expandedRowRender = (record: any, index: any, indent: any, expanded: any) => {
const childData = record.childData
const childColumns: any = [
{
title: '岗位名称',
dataIndex: 'jobTitle',
key: 'jobTitle'
},
{
title: '招聘人数',
dataIndex: 'num',
key: 'num'
},
]
return <Table columns={childColumns} dataSource={childData} pagination={false} rowSelection={childRowSelection} />
}
const onParentSelectChange = (record: any, selected: any, selectedRows: any) => {
let patentArr: any = [...parentSelectedRowKeys];
let childArr: any = [...childSelectedRowKeys];
//setChildArr:选择父Table下的所有子选项
let setChildArr = dataSource.find((d: any) => d.key === record.key).childData.map((item: any) => item.key)
//第1步 判断selected true:选中,false,取消选中
if (selected) {
//第2步,父Table选中,子Table全选中
patentArr.push(record.key)
childArr = Array.from(new Set([...setChildArr, ...childArr]))
} else {
//第2步,父Table取消选中,子Table全取消选中
patentArr.splice(patentArr.findIndex((item: any) => item === record.key), 1)
childArr = childArr.filter((item: any) => !setChildArr.some((e: any) => e === item))
}
//第3步,设置父,子的SelectedRowKeys
setParentSelectedRowKeys(patentArr)
setChildSelectedRowKeys(childArr)
}
const onParentSelectAll = (selected: any, selectedRows: any, changeRows: any) => {
let patentArr: any = [...parentSelectedRowKeys];
let setChildArr: any = [];
changeRows.forEach((e: any) => {
setChildArr = [...setChildArr, ...e.childData.map((item: any) => item.key)]
});
//第1步判断selected true:全选,false:取消全选
if (selected) {
//第2步:父Table选中,子Table全选中,设置子Table的SelectedRowKeys
patentArr = Array.from(new Set([...patentArr, ...changeRows.map((item: any) => item.key)]))
setChildSelectedRowKeys(setChildArr)
} else {
//第2步:父Table取消选中,子Table全取消选中,设置子Table的SelectedRowKeys
patentArr = patentArr.filter((item: any) => !changeRows.some((e: any) => e.key === item))
setChildSelectedRowKeys([])
}
//第3步:设置父Table的SelectedRowKeys
setParentSelectedRowKeys(patentArr)
}
const onChildSelectChange = (record: any, selected: any, selectedRows: any) => {
//record:当前操作行
//selected选中状态
//selectedRows:选择的数组
let childArr: any = [...childSelectedRowKeys];
//第1步 判断selected true:选中,false:取消选中
if (selected) {
childArr.push(record.key)
} else {
childArr.splice(childArr.findIndex((item: any) => item === record.key), 1)
}
selectedRows = selectedRows.filter((a: any) => a !== undefined)
//第2步,判断selectedRows的长度是否为data中child的长度,相等,就将父table选中,不等就不选中
for (let item of dataSource) {
if (item.childData.find((d: any) => d.key === record.key)) {
let parentArr: any = [...parentSelectedRowKeys];
if (item.childData.length === selectedRows.length) {
parentArr.push(item.key)
} else {
if (parentArr.length && parentArr.find((d: any) => d === item.key)) {
parentArr.splice(parentArr.findIndex((item1: any) => item1 === item.key), 1)
}
}
setParentSelectedRowKeys(parentArr)
break;
}
}
setChildSelectedRowKeys(childArr)
}
const onChildSelectAll = (selected: any, selectedRows: any, changeRows: any) => {
//selected:全选true 取消全选false
//selectedRows:改变后的
//changeRows:改变的所有数组
//第1步:判断selected,true:将子Table全部选中,false:将子Table全部取消选中
let childArr: any = [...childSelectedRowKeys];
if (selected) {
//全选
childArr = Array.from(new Set([...childArr, ...changeRows.map((item: any) => item.key)]))
} else {
//取消全选
childArr = childArr.filter((item: any) => !changeRows.some((e: any) => e.key === item))
}
//第2步:找到子Table对应的父Table的所在行,再判断selected,true:将父Table所在行选中,false:将父Table所在行取消选中
for (let item of dataSource) {
if (item.childData.find((d: any) => d.key === changeRows[0].key)) {
let parentArr: any = [...parentSelectedRowKeys];
if (selected) {
//全选
parentArr.push(item.key)
} else {
//取消全选
parentArr.splice(parentArr.findIndex((item: any) => item === item.key), 1)
}
setParentSelectedRowKeys(parentArr)
break;
}
}
setChildSelectedRowKeys(childArr)
}
const childRowSelection = {
selectedRowKeys: childSelectedRowKeys,
onSelect: onChildSelectChange,
onSelectAll: onChildSelectAll
}
const parentRowSelection = {
selectedRowKeys: parentSelectedRowKeys,
onSelect: onParentSelectChange,
onSelectAll: onParentSelectAll,
}
return (
<div>
<Table columns={parentColumns} dataSource={dataSource} expandable={{ expandedRowRender }} rowSelection={parentRowSelection} />
</div>
);
}