diff --git a/packages/components/table/__tests__/table-column.test.ts b/packages/components/table/__tests__/table-column.test.ts index b5d7d14deb..06d3bcd737 100644 --- a/packages/components/table/__tests__/table-column.test.ts +++ b/packages/components/table/__tests__/table-column.test.ts @@ -338,6 +338,92 @@ describe('table column', () => { expect(expectIndexs).toEqual(actualIndexs) expect(wrapper.vm.selected.length).toBe(wrapper.vm.testData.length) }) + + // #20292 + it('Maintain child selection states during data updates', async () => { + const wrapper = mount({ + components: { + ElTable, + ElTableColumn, + }, + template: ` + + + + + `, + + data() { + return { + testData: [ + { id: 0, desc: 'record 1' }, + { id: 1, desc: 'record 2' }, + { + id: 2, + desc: 'record 3', + children: [ + { id: 3, desc: 'record 3-1' }, + { id: 4, desc: 'record 3-2' }, + ], + }, + ], + } + }, + methods: { + addRow() { + this.testData.push({ id: 5, desc: 'record 4' }) + }, + removeRow() { + this.testData.pop() + }, + removeChildRow() { + this.testData[2].children.pop() + }, + }, + }) + await doubleWait() + + const getSelection = wrapper.vm.$refs.tableRef.getSelectionRows + const domArr = wrapper.findAll('.el-table__row .el-checkbox') + + let selectionKeys = [] + + domArr.forEach( + (checkbox, index) => index < 3 && checkbox.trigger('click') + ) + await doubleWait() + + selectionKeys = getSelection().map((item) => item.id) + expect(selectionKeys).toEqual([0, 1, 2, 3, 4]) + + // add + wrapper.vm.addRow() + await doubleWait() + + selectionKeys = getSelection().map((item) => item.id) + expect(selectionKeys).toEqual([0, 1, 2, 3, 4]) + + // remove + wrapper.vm.removeRow() + await doubleWait() + + selectionKeys = getSelection().map((item) => item.id) + expect(selectionKeys).toEqual([0, 1, 2, 3, 4]) + + // remove child + wrapper.vm.removeChildRow() + await doubleWait() + + selectionKeys = getSelection().map((item) => item.id) + expect(selectionKeys).toEqual([0, 1, 2, 3]) + + // remove with child + wrapper.vm.removeRow() + await doubleWait() + + selectionKeys = getSelection().map((item) => item.id) + expect(selectionKeys).toEqual([0, 1]) + }) }) describe('= index', () => { diff --git a/packages/components/table/src/store/watcher.ts b/packages/components/table/src/store/watcher.ts index 664b2ccd3c..a6dd42e4c0 100644 --- a/packages/components/table/src/store/watcher.ts +++ b/packages/components/table/src/store/watcher.ts @@ -193,7 +193,8 @@ function useWatcher() { let deleted if (rowKey.value) { deleted = [] - const dataMap = getKeysMap(data.value, rowKey.value) + const childrenKey = instance?.store?.states?.childrenColumnName.value + const dataMap = getKeysMap(data.value, rowKey.value, true, childrenKey) for (const key in selectedMap.value) { if (hasOwn(selectedMap.value, key) && !dataMap[key]) { deleted.push(selectedMap.value[key].row) diff --git a/packages/components/table/src/util.ts b/packages/components/table/src/util.ts index 315730f9ce..878e0c22ee 100644 --- a/packages/components/table/src/util.ts +++ b/packages/components/table/src/util.ts @@ -196,12 +196,24 @@ export const getRowIdentity = ( export const getKeysMap = function ( array: T[], - rowKey: string + rowKey: string, + flatten = false, + childrenKey = 'children' ): Record { + const data = array || [] const arrayMap = {} - ;(array || []).forEach((row, index) => { + + data.forEach((row, index) => { arrayMap[getRowIdentity(row, rowKey)] = { row, index } + + if (flatten) { + const children = row[childrenKey] + if (isArray(children)) { + Object.assign(arrayMap, getKeysMap(children, rowKey, true, childrenKey)) + } + } }) + return arrayMap }