Skip to content

Commit 6e5db1f

Browse files
authored
Merge pull request #10 from JelteMX/bugfix/performance_issues
2 parents 56df8ba + 4eb2b08 commit 6e5db1f

10 files changed

+2566
-2523
lines changed

.eslintrc.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module.exports = {
77
"@typescript-eslint/no-empty-interface": "off",
88
"@typescript-eslint/no-empty-function": "warn",
99
"react/no-find-dom-node": "off",
10-
"react/no-deprecated": "warn"
10+
"react/no-deprecated": "warn",
11+
"react/prop-types": "warn"
1112
}
1213
};

package-lock.json

+2,351-2,454
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "dynamictable",
33
"widgetName": "DynamicTable",
4-
"version": "1.3.2",
4+
"version": "1.3.3",
55
"description": "Dynamic (Tree) Table for Mendix",
66
"copyright": "Jelte Lagendijk 2019",
77
"author": "Jelte Lagendijk <jelte.lagendijk@mendix.com>",
@@ -32,7 +32,7 @@
3232
},
3333
"license": "Apache-2.0",
3434
"devDependencies": {
35-
"@mendix/pluggable-widgets-tools": "^8.6.0",
35+
"@mendix/pluggable-widgets-tools": "8.6.0",
3636
"@types/big.js": "^4.0.5",
3737
"@types/classnames": "^2.2.9",
3838
"@types/enzyme": "^3.1.10",

src/DynamicTable.tsx

+115-19
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ import {
2525
entityIsPersistable
2626
} from "@jeltemx/mendix-react-widget-utils";
2727
import { createHelperObject } from "./util/helperobject";
28-
import { getTitleFromObject, ClickCellType } from "./util/titlehelper";
29-
import { TitleMethod } from "./store/objects/abstract/table-object";
28+
import { getTitleFromObject, ClickCellType, getStaticTitleFromObject } from "./util/titlehelper";
29+
import { TitleMethod, TableObjectGetOptions, StaticTitleMethod } from "./store/objects/abstract/table-object";
3030
import { TableRecord } from "./util/table";
3131
import { getObject } from "@jeltemx/mendix-react-widget-utils";
3232
import { ValidateExtraProps, validateProps } from "./util/validation";
@@ -263,17 +263,52 @@ class DynamicTable extends Component<DynamicTableContainerProps> {
263263
columnSortingAttribute
264264
} = this.props;
265265
if (axis === "row") {
266-
this.store.setRows(objects, this.rowChildReference, this.hasChildAttr, parent, clean, {
266+
const tableOptions: TableObjectGetOptions = {
267267
classMethod: this.getClassMethod(rowClassAttr),
268-
sortMethod: this.getSortMethod(rowSortingAttribute),
269-
titleMethod: this.getTitleMethod(rowTitleType, rowTitleAttr, rowTitleNanoflow, "row")
270-
});
268+
sortMethod: this.getSortMethod(rowSortingAttribute)
269+
};
270+
271+
if (rowTitleType === "attribute" && rowTitleAttr) {
272+
tableOptions.staticTitleMethod = this.getTitleMethod(
273+
rowTitleType,
274+
rowTitleAttr,
275+
rowTitleNanoflow,
276+
"row"
277+
) as StaticTitleMethod;
278+
} else {
279+
tableOptions.titleMethod = this.getTitleMethod(
280+
rowTitleType,
281+
rowTitleAttr,
282+
rowTitleNanoflow,
283+
"row"
284+
) as TitleMethod;
285+
}
286+
287+
this.store.setRows(objects, this.rowChildReference, this.hasChildAttr, parent, clean, tableOptions);
271288
} else {
272-
this.store.setColumns(objects, {
289+
const tableOptions: TableObjectGetOptions = {
273290
classMethod: this.getClassMethod(columnClassAttr),
274-
sortMethod: this.getSortMethod(columnSortingAttribute),
275-
titleMethod: this.getTitleMethod(columnTitleType, columnTitleAttr, columnTitleNanoflow, "column")
276-
});
291+
sortMethod: this.getSortMethod(columnSortingAttribute)
292+
// titleMethod: this.getTitleMethod(columnTitleType, columnTitleAttr, columnTitleNanoflow, "column")
293+
};
294+
295+
if (columnTitleType === "attribute" && columnTitleAttr) {
296+
tableOptions.staticTitleMethod = this.getTitleMethod(
297+
columnTitleType,
298+
columnTitleAttr,
299+
columnTitleNanoflow,
300+
"column"
301+
) as StaticTitleMethod;
302+
} else {
303+
tableOptions.titleMethod = this.getTitleMethod(
304+
columnTitleType,
305+
columnTitleAttr,
306+
columnTitleNanoflow,
307+
"column"
308+
) as TitleMethod;
309+
}
310+
311+
this.store.setColumns(objects, tableOptions);
277312
}
278313
}
279314

@@ -282,11 +317,25 @@ class DynamicTable extends Component<DynamicTableContainerProps> {
282317
attribute: string,
283318
nanoflow: Nanoflow,
284319
nodeType: NodeType = "unknown"
285-
): TitleMethod {
320+
): TitleMethod | StaticTitleMethod {
286321
const renderAsHTML =
287322
(this.props.rowRenderAsHTML && nodeType === "row") ||
288323
(this.props.columnRenderAsHTML && nodeType === "column") ||
289324
(this.props.entryRenderAsHTML && nodeType === "entry");
325+
326+
if (titleType === "attribute" && attribute) {
327+
return (obj: mendix.lib.MxObject): ReactNode =>
328+
getStaticTitleFromObject(obj, {
329+
attribute,
330+
executeAction: this.executeAction,
331+
nanoflow,
332+
titleType,
333+
nodeType,
334+
onClickMethod: () => this.clickTypeHandler(obj, nodeType, "single"),
335+
onDoubleClickMethod: () => this.clickTypeHandler(obj, nodeType, "double"),
336+
renderAsHTML
337+
});
338+
}
290339
return (obj: mendix.lib.MxObject): Promise<ReactNode> =>
291340
getTitleFromObject(obj, {
292341
attribute,
@@ -486,10 +535,33 @@ class DynamicTable extends Component<DynamicTableContainerProps> {
486535

487536
if (entryObjects) {
488537
if (setStore) {
489-
this.store.setEntries(entryObjects, this.entryRowReference, this.entryColumnReference, clean, {
490-
classMethod: this.getClassMethod(entryClassAttr),
491-
titleMethod: this.getTitleMethod(entryTitleType, entryTitleAttr, entryTitleNanoflow, "entry")
492-
});
538+
const entriesOptions: TableObjectGetOptions = {
539+
classMethod: this.getClassMethod(entryClassAttr)
540+
};
541+
542+
if (entryTitleType === "attribute" && entryTitleAttr) {
543+
entriesOptions.staticTitleMethod = this.getTitleMethod(
544+
entryTitleType,
545+
entryTitleAttr,
546+
entryTitleNanoflow,
547+
"entry"
548+
) as StaticTitleMethod;
549+
} else {
550+
entriesOptions.titleMethod = this.getTitleMethod(
551+
entryTitleType,
552+
entryTitleAttr,
553+
entryTitleNanoflow,
554+
"entry"
555+
) as TitleMethod;
556+
}
557+
558+
this.store.setEntries(
559+
entryObjects,
560+
this.entryRowReference,
561+
this.entryColumnReference,
562+
clean,
563+
entriesOptions
564+
);
493565
} else {
494566
return entryObjects;
495567
}
@@ -541,10 +613,34 @@ class DynamicTable extends Component<DynamicTableContainerProps> {
541613
const entries = await this.entriesLoad(guids, false);
542614
if (entries) {
543615
const { entryTitleType, entryTitleAttr, entryTitleNanoflow, entryClassAttr } = this.props;
544-
this.store.setEntries(entries, this.entryRowReference, this.entryColumnReference, false, {
545-
classMethod: this.getClassMethod(entryClassAttr),
546-
titleMethod: this.getTitleMethod(entryTitleType, entryTitleAttr, entryTitleNanoflow, "entry")
547-
});
616+
617+
const entriesOptions: TableObjectGetOptions = {
618+
classMethod: this.getClassMethod(entryClassAttr)
619+
};
620+
621+
if (entryTitleType === "attribute" && entryTitleAttr) {
622+
entriesOptions.staticTitleMethod = this.getTitleMethod(
623+
entryTitleType,
624+
entryTitleAttr,
625+
entryTitleNanoflow,
626+
"entry"
627+
) as StaticTitleMethod;
628+
} else {
629+
entriesOptions.titleMethod = this.getTitleMethod(
630+
entryTitleType,
631+
entryTitleAttr,
632+
entryTitleNanoflow,
633+
"entry"
634+
) as TitleMethod;
635+
}
636+
637+
this.store.setEntries(
638+
entries,
639+
this.entryRowReference,
640+
this.entryColumnReference,
641+
false,
642+
entriesOptions
643+
);
548644
}
549645
}
550646
this.store.setLoading(false);

src/DynamicTable.xml

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
<propertyGroup caption="UI Title">
6565
<property key="rowTitleType" type="enumeration" defaultValue="attribute">
6666
<caption>Row Title Type</caption>
67-
<description></description>
67+
<description>Warning: When rendering large datasets, it is advised to only use an Attribute, not a Nanoflow. Using a Nanoflow for your title slows down the rendering of the table.</description>
6868
<enumerationValues>
6969
<enumerationValue key="attribute">Attribute</enumerationValue>
7070
<enumerationValue key="nanoflow">Nanoflow</enumerationValue>
@@ -204,7 +204,7 @@
204204
<propertyGroup caption="UI Title">
205205
<property key="columnTitleType" type="enumeration" defaultValue="attribute">
206206
<caption>Column Title Type</caption>
207-
<description></description>
207+
<description>Warning: When rendering large datasets, it is advised to only use an Attribute, not a Nanoflow. Using a Nanoflow for your title slows down the rendering of the table.</description>
208208
<enumerationValues>
209209
<enumerationValue key="attribute">Attribute</enumerationValue>
210210
<enumerationValue key="nanoflow">Nanoflow</enumerationValue>
@@ -280,7 +280,7 @@
280280
<propertyGroup caption="UI Title">
281281
<property key="entryTitleType" type="enumeration" defaultValue="attribute">
282282
<caption>Entry Title Type</caption>
283-
<description></description>
283+
<description>Warning: When rendering large datasets, it is advised to only use an Attribute, not a Nanoflow. Using a Nanoflow for your title slows down the rendering of the table.</description>
284284
<enumerationValues>
285285
<enumerationValue key="attribute">Attribute</enumerationValue>
286286
<enumerationValue key="nanoflow">Nanoflow</enumerationValue>

src/components/DynamicTreeTableContainer.tsx

+9-11
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,8 @@ export class DynamicTreeTableContainer extends Component<DynamicTreeTableContain
3939

4040
render(): ReactNode {
4141
const { selectMode, clickToSelect, store, hideSelectBoxes, className, ui } = this.props;
42-
const { tableColumns, tableRows, isLoading, selectedRowsIds, width } = store;
4342

44-
const { removeValidationMessage, validationMessages } = store;
45-
const removeValidation = removeValidationMessage.bind(store);
43+
const removeValidation = store.removeValidationMessage.bind(store);
4644

4745
const clearDebounce = (): void => {
4846
if (this.debounce !== null) {
@@ -58,7 +56,7 @@ export class DynamicTreeTableContainer extends Component<DynamicTreeTableContain
5856
this.debounce = window.setTimeout(() => {
5957
// this.onRowClick(record);
6058
if (selectMode && selectMode !== "none" && clickToSelect) {
61-
const selected = [...selectedRowsIds];
59+
const selected = [...store.selectedRowsIds];
6260
const findKey = selected.findIndex(s => s === record.key);
6361
const isSelected = findKey !== -1;
6462
if (isSelected && selectMode === "single") {
@@ -89,14 +87,14 @@ export class DynamicTreeTableContainer extends Component<DynamicTreeTableContain
8987
if (selectMode && selectMode !== "none") {
9088
rowSelection = {
9189
type: "checkbox",
92-
selectedRowKeys: selectedRowsIds,
90+
selectedRowKeys: store.selectedRowsIds,
9391
onChange: (keys: string[]): void => {
9492
if (selectMode === "multi") {
9593
store.setSelected(keys);
9694
}
9795
},
9896
onSelectAll: (): void => {
99-
if (selectMode === "single" && selectedRowsIds.length > 0) {
97+
if (selectMode === "single" && store.selectedRowsIds.length > 0) {
10098
store.setSelected([]);
10199
}
102100
},
@@ -128,15 +126,15 @@ export class DynamicTreeTableContainer extends Component<DynamicTreeTableContain
128126
heightUnit={ui.settingsHeightUnit}
129127
>
130128
<Table
131-
columns={this.getColumns(tableColumns)}
132-
dataSource={tableRows}
133-
loading={isLoading}
129+
columns={this.getColumns(store.tableColumns)}
130+
dataSource={store.tableRows}
131+
loading={store.isLoading}
134132
onExpand={this.onExpand}
135133
onRow={onRow}
136134
rowSelection={rowSelection}
137135
pagination={false}
138136
rowClassName={this.onRowClassName}
139-
scroll={{ x: width || true, y: scrollY }}
137+
scroll={{ x: store.width || true, y: scrollY }}
140138
size="small"
141139
/>
142140
<ReactResizeDetector
@@ -157,7 +155,7 @@ export class DynamicTreeTableContainer extends Component<DynamicTreeTableContain
157155
className
158156
)}
159157
>
160-
<Alerts validationMessages={validationMessages} remove={removeValidation} />
158+
<Alerts validationMessages={store.validationMessages} remove={removeValidation} />
161159
{containerIfNotDisabled}
162160
</div>
163161
);

src/package.xml

+1-1
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="DynamicTable" version="1.3.2" xmlns="http://www.mendix.com/clientModule/1.0/">
3+
<clientModule name="DynamicTable" version="1.3.3" xmlns="http://www.mendix.com/clientModule/1.0/">
44
<widgetFiles>
55
<widgetFile path="DynamicTable.xml"/>
66
</widgetFiles>

src/store/objects/abstract/table-object.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import { computed, flow, observable, action } from "mobx";
22
import { ReactNode } from "react";
33

44
export type TitleMethod = ((obj: mendix.lib.MxObject) => Promise<ReactNode | string>) | null;
5+
export type StaticTitleMethod = ((obj: mendix.lib.MxObject) => ReactNode | string) | null;
56
export type SortMethod = ((obj: mendix.lib.MxObject) => string | number | null) | null;
67
export type ClassMethod = ((obj: mendix.lib.MxObject) => string) | null;
78

89
export interface TableObjectGetOptions {
910
titleMethod?: TitleMethod;
11+
staticTitleMethod?: StaticTitleMethod;
1012
classMethod?: ClassMethod;
1113
sortMethod?: SortMethod;
1214
}
@@ -15,6 +17,7 @@ export interface TableObjectOptions {
1517
mxObject: mendix.lib.MxObject;
1618
changeHandler?: (guid?: string, removedCb?: (removed: boolean) => void) => void | Promise<void>;
1719
getMethods: TableObjectGetOptions;
20+
title?: string;
1821
}
1922

2023
export class TableObject {
@@ -24,6 +27,7 @@ export class TableObject {
2427
public _changeHandler: (guid?: string, removedCb?: (removed: boolean) => void) => void;
2528

2629
public _titleMethod: TitleMethod;
30+
public _staticTitleMethod: StaticTitleMethod;
2731
public _classMethod: ClassMethod;
2832
public _sortMethod: SortMethod;
2933

@@ -40,13 +44,14 @@ export class TableObject {
4044

4145
constructor(opts: TableObjectOptions) {
4246
const { mxObject, changeHandler, getMethods } = opts;
43-
const { titleMethod, classMethod, sortMethod } = getMethods;
47+
const { titleMethod, staticTitleMethod, classMethod, sortMethod } = getMethods;
4448
this._obj = mxObject;
4549

46-
this._title = "";
50+
this._title = opts.title || "";
4751
this._sortKey = null;
4852
this._class = "";
4953
this._titleMethod = titleMethod || null;
54+
this._staticTitleMethod = staticTitleMethod || null;
5055
this._classMethod = classMethod || null;
5156
this._sortMethod = sortMethod || null;
5257
this._changeHandler = changeHandler || ((): void => {});
@@ -58,6 +63,9 @@ export class TableObject {
5863

5964
if (titleMethod) {
6065
this.fixTitle();
66+
} else if (staticTitleMethod) {
67+
// @ts-ignore
68+
this._title = staticTitleMethod(mxObject);
6169
}
6270

6371
if (classMethod) {
@@ -111,7 +119,13 @@ export class TableObject {
111119
window.logger.debug(`Removed: ${this._type} || ${guid}`);
112120
}
113121
} else {
114-
this.fixTitle();
122+
if (this._titleMethod) {
123+
this.fixTitle();
124+
} else if (this._staticTitleMethod) {
125+
// @ts-ignore
126+
this._title = this._staticTitleMethod(this._obj);
127+
}
128+
115129
this.fixSorting();
116130
this.fixClass();
117131
}

0 commit comments

Comments
 (0)