Skip to content

Commit f3faeeb

Browse files
authored
Merge pull request #3943 from VisActor/feat/parent_child_selected_sync
Feat/parent child selected sync
2 parents 5ebb9a0 + 542df55 commit f3faeeb

11 files changed

Lines changed: 156 additions & 22 deletions

File tree

docs/assets/demo/en/table-type/list-table-tree-lazy-load.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Basic table tree display, turn on the tree mode of a certain column, if the chil
1717
- children: true Set to enable tree display on a certain row of data and lazily load child node data
1818
- setRecordChildren(children: any[], col: number, row: number) Call this method after lazily loading child node data in a row of data and return it to the table component
1919
- TREE_HIERARCHY_STATE_CHANGE tree display state change events
20+
- cellType: 'checkbox' Turns on the checkbox. Use it with tree:true to display the checkbox in a tree format.
21+
- enableCheckboxCascade: true It is used globally to turn on the checkbox cascade. It must be used with cellType: 'checkbox' and tree:true to synchronize the parent and child element selections.
2022

2123
## Code Demo
2224

@@ -184,6 +186,9 @@ const option = {
184186
columns: [
185187
{
186188
field: 'category',
189+
// Supports checkbox tree display.
190+
// To synchronize parent and child element checkboxes, be sure to configure enableCheckboxCascade: true in the option global configuration.
191+
// cellType: 'checkbox',
187192
tree: true,
188193
title: 'category',
189194
width: 'auto',
@@ -203,6 +208,7 @@ const option = {
203208
sort: true
204209
}
205210
],
211+
// enableCheckboxCascade:true,
206212
showPin: true, //显示VTable内置冻结列图标
207213
widthMode: 'standard',
208214
allowFrozenColCount: 2,

docs/assets/demo/zh/table-type/list-table-tree-lazy-load.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ option: ListTable-columns-text#tree
1717
- children: true 在某一行数据上设置开启树形展示 并懒加载子节点数据
1818
- setRecordChildren(children: any[], col: number, row: number) 在某一行数据懒加载子节点数据后调用此方法回传到表格组件中
1919
- TREE_HIERARCHY_STATE_CHANGE 树形展示状态改变事件
20+
- cellType: 'checkbox' 开启复选框,与 tree:true 配合使用可进行复选框树形展示
21+
- enableCheckboxCascade: true 在全局使用,用于开启复选框级联,必须与 cellType: 'checkbox'和 tree:true 配合使用,可实现父子元素勾选同步
2022

2123
## 代码演示
2224

@@ -184,6 +186,9 @@ const option = {
184186
columns: [
185187
{
186188
field: '类别',
189+
// 支持checkbox复选框树形展示。
190+
// 欲使父子级元素勾选同步时务必在option全局配置 enableCheckboxCascade: true。
191+
// cellType: 'checkbox',
187192
tree: true,
188193
title: '类别',
189194
width: 'auto',
@@ -203,6 +208,7 @@ const option = {
203208
sort: true
204209
}
205210
],
211+
// enableCheckboxCascade:true,
206212
showPin: true, //显示VTable内置冻结列图标
207213
widthMode: 'standard',
208214
allowFrozenColCount: 2,

packages/vtable/examples/list/list-checkbox-tree.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export function createTable() {
148148
field: '类别',
149149
tree: true,
150150
cellType: 'checkbox',
151-
enableTreeCheckbox: true,
151+
// headerType: 'checkbox',
152152
title: '类别',
153153
width: 'auto',
154154
sort: true
@@ -185,7 +185,8 @@ export function createTable() {
185185
defaultRowHeight: 32,
186186
select: {
187187
disableDragSelect: true
188-
}
188+
},
189+
enableCheckboxCascade: true
189190
};
190191

191192
const instance = new ListTable(option);

packages/vtable/examples/list/list-tree-checkbox.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ export function createTable() {
122122

123123
const data = [
124124
{
125+
// _vtable_rowSeries_number:{text: 'checked', checked: true, disable: true },
125126
类别: '办公用品',
126127
销售额: '129.696',
127128
数量: '2',

packages/vtable/src/core/BaseTable.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI {
281281
keyboardOptions,
282282
eventOptions,
283283
rowSeriesNumber,
284+
enableCheckboxCascade,
284285
// columnSeriesNumber,
285286
// disableRowHeaderColumnResize,
286287
columnResizeMode,
@@ -393,6 +394,7 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI {
393394
internalProps.keyboardOptions = keyboardOptions;
394395
internalProps.eventOptions = eventOptions;
395396
internalProps.rowSeriesNumber = rowSeriesNumber;
397+
internalProps.enableCheckboxCascade = enableCheckboxCascade;
396398
// internalProps.columnSeriesNumber = columnSeriesNumber;
397399

398400
internalProps.columnResizeMode = resize?.columnResizeMode ?? columnResizeMode;
@@ -2390,6 +2392,7 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI {
23902392
keyboardOptions,
23912393
eventOptions,
23922394
rowSeriesNumber,
2395+
enableCheckboxCascade,
23932396
// columnSeriesNumber,
23942397
// disableRowHeaderColumnResize,
23952398
columnResizeMode,
@@ -2471,6 +2474,7 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI {
24712474
internalProps.keyboardOptions = keyboardOptions;
24722475
internalProps.eventOptions = eventOptions;
24732476
internalProps.rowSeriesNumber = rowSeriesNumber;
2477+
internalProps.enableCheckboxCascade = enableCheckboxCascade;
24742478
// internalProps.columnSeriesNumber = columnSeriesNumber;
24752479

24762480
internalProps.columnResizeMode = resize?.columnResizeMode ?? columnResizeMode;

packages/vtable/src/event/self-event-listener/list-table/checkbox.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { isArray, isNumber } from '@visactor/vutils';
2-
import type { BaseTableAPI, ListTableProtected } from '../../../ts-types/base-table';
2+
import type { BaseTableAPI } from '../../../ts-types/base-table';
33
import { setCellCheckboxStateByAttribute } from '../../../state/checkbox/checkbox';
44
import type { ListTableAPI } from '../../../ts-types';
55
import { HierarchyState } from '../../../ts-types';
@@ -9,7 +9,10 @@ export function bindGroupTitleCheckboxChange(table: BaseTableAPI) {
99
table.on('checkbox_state_change', args => {
1010
const { col, row, checked, field } = args;
1111

12-
if (field !== '_vtable_rowSeries_number' || table.internalProps.rowSeriesNumber?.enableTreeCheckbox !== true) {
12+
if (
13+
!table.internalProps.layoutMap.isSeriesNumber(col, row) ||
14+
table.internalProps.rowSeriesNumber?.enableTreeCheckbox !== true
15+
) {
1316
return;
1417
}
1518

@@ -30,7 +33,7 @@ export function bindGroupTitleCheckboxChange(table: BaseTableAPI) {
3033
// 1.1 group title check
3134
// 1.1.1 check all children
3235
if (getHierarchyState(table, col, row) === HierarchyState.collapse) {
33-
updateChildrenCheckboxState(true, titleIndex, table, field);
36+
updateChildrenCheckboxState(true, titleIndex, table, field as string);
3437
} else {
3538
setAllChildrenCheckboxState(true, titleShowIndex, titleIndex, indexedData, table, col);
3639
}
@@ -40,7 +43,7 @@ export function bindGroupTitleCheckboxChange(table: BaseTableAPI) {
4043
// 1.2 group title uncheck
4144
// 1.2.1 uncheck all children
4245
if (getHierarchyState(table, col, row) === HierarchyState.collapse) {
43-
updateChildrenCheckboxState(false, titleIndex, table, field);
46+
updateChildrenCheckboxState(false, titleIndex, table, field as string);
4447
} else {
4548
setAllChildrenCheckboxState(false, titleShowIndex, titleIndex, indexedData, table, col);
4649
}
@@ -66,9 +69,8 @@ export function bindGroupCheckboxTreeChange(table: ListTableAPI) {
6669
table.on('checkbox_state_change', args => {
6770
const { col, row, checked, field } = args;
6871

69-
const isCheckboxAndTree =
70-
table.internalProps.columns.some(column => column.tree && (column as any).enableTreeCheckbox) &&
71-
field !== '_vtable_rowSeries_number';
72+
const isCheckboxAndTree = table.internalProps.columns.some(column => column.tree);
73+
table.internalProps.enableCheckboxCascade && field !== '_vtable_rowSeries_number';
7274

7375
if (!isCheckboxAndTree) {
7476
return;
@@ -200,12 +202,16 @@ function updateParentCheckboxState(
200202
});
201203
const stateArr = keys.map(key => checkedState.get(key));
202204

205+
// currentIndex的子元素
206+
const childOfCurrentIndex = (keys as string[]).filter(item => item.startsWith(key + ',') && item !== key);
207+
203208
stateArr.forEach((state, i) => {
204209
const index = keys[i] as string;
205210
const value = state;
211+
const isChildOfCurrentIndex = childOfCurrentIndex.includes(index);
212+
206213
if (start) {
207-
const indexData = index.split(',');
208-
if (indexData.length === currentIndexLength) {
214+
if (!isChildOfCurrentIndex) {
209215
start = false;
210216
} else {
211217
result.push(value[fieldName]);

packages/vtable/src/layout/simple-header-layout.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export class SimpleHeaderLayoutMap implements LayoutMapAPI {
142142
style: rowSeriesNumber.style,
143143
width: rowSeriesNumber.width,
144144
format: rowSeriesNumber.format,
145-
field: '_vtable_rowSeries_number', //rowSeriesNumber.field,
145+
field: rowSeriesNumber.field,
146146
icon: rowSeriesNumber.icon,
147147
headerIcon: rowSeriesNumber.headerIcon,
148148
isChildNode: false

packages/vtable/src/scenegraph/group-creater/cell-type/checkbox-cell.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import type { IThemeSpec } from '@src/vrender';
22
import { Group } from '../../graphic/group';
3-
import type {
4-
CellInfo,
5-
CellRange,
6-
CheckboxColumnDefine,
7-
CheckboxStyleOption,
8-
ColumnIconOption,
9-
SparklineSpec
3+
import {
4+
InternalIconName,
5+
type CellInfo,
6+
type CellRange,
7+
type CheckboxColumnDefine,
8+
type CheckboxStyleOption,
9+
type ColumnIconOption,
10+
type SparklineSpec
1011
} from '../../../ts-types';
1112
import type { BaseTableAPI } from '../../../ts-types/base-table';
1213
import { isObject } from '@visactor/vutils';
@@ -20,6 +21,7 @@ import { getCellBorderStrokeWidth } from '../../utils/cell-border-stroke-width';
2021
import { dealWithIcon, dealWithIconLayout } from '../../utils/text-icon-layout';
2122
import { CheckboxContent } from '../../component/checkbox-content';
2223
import { CUSTOM_CONTAINER_NAME } from '../../component/custom';
24+
import type { ListTable } from '../../..';
2325

2426
export function createCheckboxCellGroup(
2527
cellGroup: Group | null,
@@ -164,7 +166,12 @@ export function createCheckboxCellGroup(
164166
isCheckboxTree
165167
);
166168

167-
if (cellContentLeftIcons.length !== 0 || cellContentRightIcons.length !== 0) {
169+
// 目前只支持展示折叠或者展开icons
170+
if (
171+
cellContentLeftIcons.length === 1 &&
172+
(cellContentLeftIcons[0].name === InternalIconName.expandIconName ||
173+
cellContentLeftIcons[0].name === InternalIconName.collapseIconName)
174+
) {
168175
const checkContent = new CheckboxContent({
169176
x: 0,
170177
y: 0,
@@ -325,6 +332,15 @@ function createCheckbox(
325332
isChecked = value;
326333
text = '';
327334
}
335+
// 处理 rowSeriesNumbe 在record设置checkbox是否勾选与是否禁用的场景
336+
if (table.internalProps.layoutMap.isSeriesNumber(col, row)) {
337+
const checkboxSeriesNumberStyle = (table as ListTable).getFieldData(define.field, col, row);
338+
if (checkboxSeriesNumberStyle) {
339+
isChecked = checkboxSeriesNumberStyle.checked;
340+
isDisabled = checkboxSeriesNumberStyle.disable;
341+
text = checkboxSeriesNumberStyle.text ?? '';
342+
}
343+
}
328344
isChecked = table.stateManager.syncCheckedState(col, row, define.field as string | number, isChecked);
329345
const hierarchyOffset = getHierarchyOffset(col, row, table);
330346
const cellStyle = table._getCellStyle(col, row) as CheckboxStyleOption; // to be fixed

packages/vtable/src/scenegraph/scenegraph.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ import { updateReactContainer } from './layout/frozen-react';
7676

7777
import * as registerIcons from '../icons';
7878
import { temporarilyUpdateSelectRectStyle } from './select/update-select-style';
79+
import type { CheckboxContent } from './component/checkbox-content';
7980
// import { contextModule } from './context/module';
8081

8182
registerForVrender();
@@ -803,6 +804,28 @@ export class Scenegraph {
803804
(node as CheckBox).setAttribute('checked', checked);
804805
}
805806
}
807+
// 适配cellType: 'checkbox'与tree: true,并且开启enableTreeCheckbox: true的情况
808+
if (node.name === 'checkbox-content') {
809+
if (checked === 'indeterminate') {
810+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
811+
'indeterminate',
812+
true
813+
);
814+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
815+
'checked',
816+
undefined
817+
);
818+
} else {
819+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
820+
'indeterminate',
821+
undefined
822+
);
823+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
824+
'checked',
825+
checked
826+
);
827+
}
828+
}
806829
});
807830
});
808831
} else {
@@ -818,6 +841,28 @@ export class Scenegraph {
818841
(node as CheckBox).setAttribute('checked', checked);
819842
}
820843
}
844+
// 适配cellType: 'checkbox'与tree: true,并且开启enableTreeCheckbox: true的情况
845+
if (node.name === 'checkbox-content') {
846+
if (checked === 'indeterminate') {
847+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
848+
'indeterminate',
849+
true
850+
);
851+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
852+
'checked',
853+
undefined
854+
);
855+
} else {
856+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
857+
'indeterminate',
858+
undefined
859+
);
860+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
861+
'checked',
862+
checked
863+
);
864+
}
865+
}
821866
});
822867
});
823868
}
@@ -838,6 +883,28 @@ export class Scenegraph {
838883
(node as CheckBox).setAttribute('checked', checked);
839884
}
840885
}
886+
// 适配cellType: 'checkbox'与tree: true,并且开启enableTreeCheckbox: true的情况
887+
if (node.name === 'checkbox-content') {
888+
if (checked === 'indeterminate') {
889+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
890+
'indeterminate',
891+
true
892+
);
893+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
894+
'checked',
895+
undefined
896+
);
897+
} else {
898+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
899+
'indeterminate',
900+
undefined
901+
);
902+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
903+
'checked',
904+
checked
905+
);
906+
}
907+
}
841908
});
842909
});
843910
} else {
@@ -853,6 +920,28 @@ export class Scenegraph {
853920
(node as CheckBox).setAttribute('checked', checked);
854921
}
855922
}
923+
// 适配cellType: 'checkbox'与tree: true,并且开启enableTreeCheckbox: true的情况
924+
if (node.name === 'checkbox-content') {
925+
if (checked === 'indeterminate') {
926+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
927+
'indeterminate',
928+
true
929+
);
930+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
931+
'checked',
932+
undefined
933+
);
934+
} else {
935+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
936+
'indeterminate',
937+
undefined
938+
);
939+
((node as CheckboxContent)._checkboxGroup.getChildByName('checkbox') as CheckBox).setAttribute(
940+
'checked',
941+
checked
942+
);
943+
}
944+
}
856945
});
857946
});
858947
}

packages/vtable/src/ts-types/base-table.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ export interface IBaseTableProtected {
132132
keyboardOptions?: TableKeyboardOptions;
133133
eventOptions?: TableEventOptions;
134134
rowSeriesNumber?: IRowSeriesNumber;
135+
/** 启动复选框级联 */
136+
enableCheckboxCascade?: boolean;
135137
columnSeriesNumber?: ColumnSeriesNumber[];
136138
// disableRowHeaderColumnResize?: boolean;
137139

@@ -537,6 +539,8 @@ export interface BaseTableConstructorOptions {
537539
beforeRender?: (stage: any) => void;
538540
afterRender?: (stage: any) => void;
539541
rowSeriesNumber?: IRowSeriesNumber;
542+
/** 启用复选框级联 */
543+
enableCheckboxCascade?: boolean;
540544
// columnSeriesNumber?: ColumnSeriesNumber[];
541545
customCellStyle?: CustomCellStyle[];
542546
customCellStyleArrangement?: CustomCellStyleArrangement[];

0 commit comments

Comments
 (0)