Skip to content

Commit 92b303c

Browse files
authored
Add option to automatically select/deselect children on multiselect (#25)
1 parent ea52c69 commit 92b303c

File tree

11 files changed

+116
-22
lines changed

11 files changed

+116
-22
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
dist: xenial
22
language: node_js
33
node_js:
4-
- 10
4+
- 14
55
cache: npm
66
branches:
77
only:

assets/tab07-selection.png

1.75 KB
Loading

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "mxtreetable",
33
"widgetName": "MxTreeTable",
4-
"version": "2.0.8",
4+
"version": "2.1.0",
55
"description": "TreeTable widget",
66
"copyright": "Mendix 2019",
77
"author": "Jelte Lagendijk <jelte.lagendijk@mendix.com>",

src/MxTreeTable.tsx

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -703,18 +703,47 @@ Your context object is of type "${contextEntity}". Please check the configuratio
703703
}
704704
}
705705

706-
private onSelect(ids: string[]): void {
707-
const { selectMode, mxObject } = this.props;
706+
private onSelect(ids: string[], childChange?: { record: TableRecord; selected: boolean }): void {
707+
const { selectMode, selectMultiChildren, mxObject } = this.props;
708+
709+
let selectedIDS = ids;
710+
708711
if (selectMode === "none") {
709712
return;
710713
}
711714
if (mxObject) {
715+
let additions: string[] = [];
716+
let removals: string[] = [];
717+
718+
if (selectMode === "multi" && selectMultiChildren && childChange) {
719+
const row = this.store.findRowObject(childChange.record.key);
720+
if (row) {
721+
const children = this.store.findChildren(row);
722+
if (children.length > 0) {
723+
const ids = children.map(c => c.key);
724+
if (childChange.selected) {
725+
additions = ids;
726+
} else {
727+
removals = ids;
728+
}
729+
}
730+
}
731+
}
732+
712733
try {
713734
const { selectedRows } = this.store;
714-
const unTouched = selectedRows.filter(row => ids.indexOf(row) !== -1);
715-
const newIds = ids.filter(id => selectedRows.indexOf(id) === -1);
716735

717-
if (ids.length === 0 || newIds.length === 0) {
736+
if (additions.length) {
737+
selectedIDS = [...selectedIDS, ...additions.filter(a => !selectedIDS.includes(a))];
738+
}
739+
if (removals.length) {
740+
selectedIDS = selectedIDS.filter(id => !removals.includes(id));
741+
}
742+
743+
const unTouched = selectedRows.filter(row => selectedIDS.indexOf(row) !== -1);
744+
const newIds = selectedIDS.filter(id => selectedRows.indexOf(id) === -1);
745+
746+
if (selectedIDS.length === 0 || newIds.length === 0) {
718747
this.store.setSelected(unTouched);
719748
this.onSelectAction();
720749
} else {

src/MxTreeTable.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,15 @@ It should be a non-persistent entity (persistent is not permitted) with a refere
460460
</property>
461461
</propertyGroup>
462462

463+
<propertyGroup caption="Multi select">
464+
<property key="selectMultiChildren" type="boolean" defaultValue="false">
465+
<caption>Select children</caption>
466+
<description>When selecting an element in Multi select mode, you might want to automatically select the children. This is disabled by default.
467+
468+
Note: This only works properly when the whole tree is loaded (Data -> Scenario). If you apply this to a partial tree, it will obviously only send the child nodes that have been loaded.</description>
469+
</property>
470+
</propertyGroup>
471+
463472
<propertyGroup caption="Selection onChange">
464473
<property key="selectOnChangeAction" type="enumeration" defaultValue="nothing">
465474
<caption>On Change action</caption>

src/components/TreeTable.tsx

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export interface TreeTableProps {
3636
showHeader: boolean;
3737
clickToSelect: boolean;
3838
selectMode: SelectionMode;
39-
onSelect?: (ids: string[]) => void;
39+
onSelect?: (ids: string[], childChange?: { record: TableRecord; selected: boolean }) => void;
4040
buttonBar?: ReactNode;
4141
hideSelectBoxes?: boolean;
4242
renderExpandButton?: boolean;
@@ -131,23 +131,29 @@ export class TreeTable extends Component<TreeTableProps> {
131131
rowSelection = {
132132
type: "checkbox",
133133
selectedRowKeys: selectedRows,
134-
onChange: (keys: string[]) => {
135-
if (selectMode === "multi") {
136-
this.setSelected(keys);
137-
}
138-
},
139-
onSelectAll: () => {
134+
// onChange: (_keys: string[]) => {
135+
// if (selectMode === "multi") {
136+
// this.setSelected(keys);
137+
// }
138+
// },
139+
onSelectAll: (selected: boolean, selectedRows: TableRecord[]) => {
140+
const keys = selectedRows.map(row => row.key);
140141
if (selectMode === "single" && selectedRows.length > 0) {
141142
this.setSelected([]);
143+
} else if (selectMode === "multi") {
144+
this.setSelected(selected ? keys : []);
142145
}
143146
},
144147
onSelect: (record: TableRecord, selected: boolean, selectedRows: TableRecord[]) => {
148+
const keys = selectedRows.map(row => row.key);
145149
if (selectMode === "single") {
146150
if (selected) {
147151
this.setSelected([record.key]);
148152
} else {
149-
this.setSelected(selectedRows.map(row => row.key));
153+
this.setSelected(keys);
150154
}
155+
} else {
156+
this.setSelected(keys, { record, selected });
151157
}
152158
}
153159
};
@@ -233,8 +239,8 @@ export class TreeTable extends Component<TreeTableProps> {
233239
);
234240
}
235241

236-
private setSelected(keys: string[]): void {
237-
this.onSelectionChange(keys);
242+
private setSelected(keys: string[], childChange?: { record: TableRecord; selected: boolean }): void {
243+
this.onSelectionChange(keys, childChange);
238244
}
239245

240246
private rowClassName(record: TableRecord, index: number): string {
@@ -268,9 +274,9 @@ export class TreeTable extends Component<TreeTableProps> {
268274
}
269275
}
270276

271-
private onSelectionChange(ids: string[]): void {
277+
private onSelectionChange(ids: string[], childChange?: { record: TableRecord; selected: boolean }): void {
272278
if (this.props.onSelect) {
273-
this.props.onSelect(ids);
279+
this.props.onSelect(ids, childChange);
274280
}
275281
}
276282

src/package.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<package xmlns="http://www.mendix.com/package/1.0/">
3-
<clientModule name="MxTreeTable" version="2.0.8" xmlns="http://www.mendix.com/clientModule/1.0/">
3+
<clientModule name="MxTreeTable" version="2.1.0" xmlns="http://www.mendix.com/clientModule/1.0/">
44
<widgetFiles>
55
<widgetFile path="MxTreeTable.xml"/>
66
</widgetFiles>

src/store/index.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export class NodeStore {
7171
public hasChildren = this._hasChildren.bind(this);
7272
public rowChangeHandler = this._rowChangeHandler.bind(this);
7373
public findParents = this._findParents.bind(this);
74+
public findChildren = this._findChildren.bind(this);
7475
public setSelectedFromExternal = this._setSelectedFromExternal.bind(this);
7576

7677
@observable public contextObject: mendix.lib.MxObject | null;
@@ -585,6 +586,24 @@ export class NodeStore {
585586
return returnArray;
586587
}
587588

589+
private _findChildren(rowObject: RowObject): RowObject[] {
590+
let returnArray: RowObject[] = [];
591+
592+
const directChildren = this.rowObjects.filter(row => row._parent === rowObject.key);
593+
594+
if (directChildren.length > 0) {
595+
directChildren.forEach(child => {
596+
returnArray.push(child);
597+
const childChild = this._findChildren(child);
598+
returnArray = returnArray.concat(childChild);
599+
});
600+
} else {
601+
return [];
602+
}
603+
604+
return returnArray;
605+
}
606+
588607
private _rowChangeHandler(): (guid: string, removedCB: (removed: boolean) => void) => Promise<void> {
589608
return async (guid: string, removedCB: (removed: boolean) => void): Promise<void> => {
590609
this.debug("store: rowChangeHandler", guid);

typings/MxTreeTableProps.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ export interface MxTreeTableContainerProps extends CommonProps {
108108
selectClickSelect: boolean;
109109
selectHideCheckboxes: boolean;
110110
selectSelectFirstOnSingle: boolean;
111+
selectMultiChildren: boolean;
111112
selectOnChangeAction: OnChangeAction;
112113
selectOnChangeMicroflow: string;
113114
selectOnChangeNanoflow: Nanoflow;

0 commit comments

Comments
 (0)