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>
 );
}


Related articles: