Skip to content

Commit 98552d0

Browse files
authored
Merge pull request #6 from JelteMX/feature/sorting
Add sorting attribute to matrix
2 parents 2c8ca05 + 8788b4e commit 98552d0

File tree

10 files changed

+134
-10
lines changed

10 files changed

+134
-10
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Show a reference table. Rows & Columns are Mendix objects, Entry objects are in
3131
- Selection of rows (single, multi)
3232
- Events: Click/Double click on Row, Column, Entry or empty field
3333

34-
> This widget is about 580Kb uncompressed, so in your cloud deployment this widget should take about 150 Kb of network resources
34+
> This widget is about 600Kb uncompressed, so in your cloud deployment this widget should take about 160 Kb of network resources
3535
3636
Tested:
3737

assets/settings1.png

8.8 KB
Loading

assets/settings3.png

9.97 KB
Loading

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "dynamictable",
33
"widgetName": "DynamicTable",
4-
"version": "1.2.1",
4+
"version": "1.3.0",
55
"description": "Dynamic (Tree) Table for Mendix",
66
"copyright": "Jelte Lagendijk 2019",
77
"author": "Jelte Lagendijk <jelte.lagendijk@mendix.com>",

src/DynamicTable.tsx

+21-2
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,17 @@ class DynamicTable extends Component<DynamicTableContainerProps> {
6969

7070
this.bindMethods();
7171

72+
const sortingTypeRows = props.rowSortingAttribute !== "" ? props.rowSortingOrder : "none";
73+
const sortingTypeColumns = props.columnSortingAttribute !== "" ? props.columnSortingOrder : "none";
74+
7275
const validationMessages = this.getRuntimeValidations(props);
7376

7477
this.store = new TableStore({
7578
entriesLoader: this.entriesLoad,
7679
onSelectionChange: this.onSelectionChange,
77-
validationMessages
80+
validationMessages,
81+
sortingTypeRows,
82+
sortingTypeColumns
7883
});
7984
}
8085

@@ -151,6 +156,7 @@ class DynamicTable extends Component<DynamicTableContainerProps> {
151156
this.setAxisObjects = this.setAxisObjects.bind(this);
152157
this.getTitleMethod = this.getTitleMethod.bind(this);
153158
this.getClassMethod = this.getClassMethod.bind(this);
159+
this.getSortMethod = this.getSortMethod.bind(this);
154160
this.expanderFunc = this.expanderFunc.bind(this);
155161
this.onSelectionChange = this.onSelectionChange.bind(this);
156162
this.clickTypeHandler = this.clickTypeHandler.bind(this);
@@ -249,19 +255,23 @@ class DynamicTable extends Component<DynamicTableContainerProps> {
249255
rowTitleAttr,
250256
rowTitleNanoflow,
251257
rowClassAttr,
258+
rowSortingAttribute,
252259
columnTitleType,
253260
columnTitleAttr,
254261
columnTitleNanoflow,
255-
columnClassAttr
262+
columnClassAttr,
263+
columnSortingAttribute
256264
} = this.props;
257265
if (axis === "row") {
258266
this.store.setRows(objects, this.rowChildReference, this.hasChildAttr, parent, clean, {
259267
classMethod: this.getClassMethod(rowClassAttr),
268+
sortMethod: this.getSortMethod(rowSortingAttribute),
260269
titleMethod: this.getTitleMethod(rowTitleType, rowTitleAttr, rowTitleNanoflow, "row")
261270
});
262271
} else {
263272
this.store.setColumns(objects, {
264273
classMethod: this.getClassMethod(columnClassAttr),
274+
sortMethod: this.getSortMethod(columnSortingAttribute),
265275
titleMethod: this.getTitleMethod(columnTitleType, columnTitleAttr, columnTitleNanoflow, "column")
266276
});
267277
}
@@ -299,6 +309,15 @@ class DynamicTable extends Component<DynamicTableContainerProps> {
299309
};
300310
}
301311

312+
private getSortMethod(attr: string): (obj: mendix.lib.MxObject) => string | null | number {
313+
return (obj: mendix.lib.MxObject): string | null | number => {
314+
if (!obj || !attr) {
315+
return null;
316+
}
317+
return obj.get(attr) as string | number;
318+
};
319+
}
320+
302321
private async clickTypeHandler(
303322
_obj: mendix.lib.MxObject,
304323
_nodeType: NodeType = "unknown",

src/DynamicTable.xml

+42
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,27 @@
4040
<returnType type="Object" isList="true" entityProperty="rowEntity" />
4141
</property>
4242
</propertyGroup>
43+
<propertyGroup caption="Sorting">
44+
<property key="rowSortingAttribute" type="attribute" entityProperty="rowEntity" required="false">
45+
<caption>Row Sorting Attribute</caption>
46+
<description>This attribute can be used to sort the data. If not set, it will use the order of objects coming from the data source</description>
47+
<attributeTypes>
48+
<attributeType name="String" />
49+
<attributeType name="AutoNumber" />
50+
<attributeType name="Decimal" />
51+
<attributeType name="Integer" />
52+
<attributeType name="Long" />
53+
</attributeTypes>
54+
</property>
55+
<property key="rowSortingOrder" type="enumeration" defaultValue="asc">
56+
<caption>Row Sorting Order</caption>
57+
<description>The sorting order only applies when using the sorting attribute</description>
58+
<enumerationValues>
59+
<enumerationValue key="asc">Ascending</enumerationValue>
60+
<enumerationValue key="desc">Descending</enumerationValue>
61+
</enumerationValues>
62+
</property>
63+
</propertyGroup>
4364
<propertyGroup caption="UI Title">
4465
<property key="rowTitleType" type="enumeration" defaultValue="attribute">
4566
<caption>Row Title Type</caption>
@@ -159,6 +180,27 @@
159180
<returnType type="Object" isList="true" entityProperty="columnEntity" />
160181
</property>
161182
</propertyGroup>
183+
<propertyGroup caption="Sorting">
184+
<property key="columnSortingAttribute" type="attribute" entityProperty="columnEntity" required="false">
185+
<caption>Column Sorting Attribute</caption>
186+
<description>This attribute can be used to sort the data. If not set, it will use the order of objects coming from the data source</description>
187+
<attributeTypes>
188+
<attributeType name="String" />
189+
<attributeType name="AutoNumber" />
190+
<attributeType name="Decimal" />
191+
<attributeType name="Integer" />
192+
<attributeType name="Long" />
193+
</attributeTypes>
194+
</property>
195+
<property key="columnSortingOrder" type="enumeration" defaultValue="asc">
196+
<caption>Column Sorting Order</caption>
197+
<description>The sorting order only applies when using the sorting attribute</description>
198+
<enumerationValues>
199+
<enumerationValue key="asc">Ascending</enumerationValue>
200+
<enumerationValue key="desc">Descending</enumerationValue>
201+
</enumerationValues>
202+
</property>
203+
</propertyGroup>
162204
<propertyGroup caption="UI Title">
163205
<property key="columnTitleType" type="enumeration" defaultValue="attribute">
164206
<caption>Column Title Type</caption>

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

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

+26-2
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 SortMethod = ((obj: mendix.lib.MxObject) => string | number | null) | null;
56
export type ClassMethod = ((obj: mendix.lib.MxObject) => string) | null;
67

78
export interface TableObjectGetOptions {
89
titleMethod?: TitleMethod;
910
classMethod?: ClassMethod;
11+
sortMethod?: SortMethod;
1012
}
1113

1214
export interface TableObjectOptions {
@@ -23,9 +25,11 @@ export class TableObject {
2325

2426
public _titleMethod: TitleMethod;
2527
public _classMethod: ClassMethod;
28+
public _sortMethod: SortMethod;
2629

2730
@observable _title: string;
2831
@observable _class: string;
32+
@observable _sortKey: null | string | number;
2933

3034
fixTitle = flow(function*(this: TableObject) {
3135
if (this._titleMethod) {
@@ -36,18 +40,20 @@ export class TableObject {
3640

3741
constructor(opts: TableObjectOptions) {
3842
const { mxObject, changeHandler, getMethods } = opts;
39-
const { titleMethod, classMethod } = getMethods;
43+
const { titleMethod, classMethod, sortMethod } = getMethods;
4044
this._obj = mxObject;
4145

4246
this._title = "";
47+
this._sortKey = null;
4348
this._class = "";
4449
this._titleMethod = titleMethod || null;
4550
this._classMethod = classMethod || null;
51+
this._sortMethod = sortMethod || null;
4652
this._changeHandler = changeHandler || ((): void => {});
4753
this._subscriptions = [];
4854

4955
if (!changeHandler) {
50-
console.log("No changehandler for ", opts);
56+
console.warn("No changehandler for ", opts);
5157
}
5258

5359
if (titleMethod) {
@@ -58,6 +64,10 @@ export class TableObject {
5864
this.fixClass();
5965
}
6066

67+
if (sortMethod) {
68+
this.fixSorting();
69+
}
70+
6171
if (this._obj) {
6272
this.resetSubscription();
6373
}
@@ -77,6 +87,13 @@ export class TableObject {
7787
}
7888
}
7989

90+
@action
91+
fixSorting(): void {
92+
if (this._sortMethod) {
93+
this._sortKey = this._sortMethod(this._obj);
94+
}
95+
}
96+
8097
@action
8198
resetSubscription(): void {
8299
const { subscribe } = window.mx.data;
@@ -95,6 +112,8 @@ export class TableObject {
95112
}
96113
} else {
97114
this.fixTitle();
115+
this.fixSorting();
116+
this.fixClass();
98117
}
99118
});
100119
}
@@ -113,6 +132,11 @@ export class TableObject {
113132
return this._class;
114133
}
115134

135+
@computed
136+
get sortKey(): string | number | null {
137+
return this._sortKey;
138+
}
139+
116140
@computed
117141
get guid(): string {
118142
return this._obj.getGuid();

src/store/store.ts

+37-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ import { TableRecord } from "../util/table";
88
import arrayToTree, { Tree } from "array-to-tree";
99
import { getObject } from "@jeltemx/mendix-react-widget-utils";
1010
import { ValidationMessage } from "../util/validation";
11+
import sortBy from "lodash/sortBy";
1112

1213
configure({ enforceActions: "observed" });
1314

15+
export type SortingType = "none" | "asc" | "desc";
16+
1417
export interface TableGuids {
1518
context: string | null;
1619
rows?: string[];
@@ -26,6 +29,8 @@ export interface TableStoreConstructorOptions {
2629
reloadEntriesOnColChange?: boolean;
2730
reloadEntriesOnRowChange?: boolean;
2831
validationMessages?: ValidationMessage[];
32+
sortingTypeRows?: SortingType;
33+
sortingTypeColumns?: SortingType;
2934
}
3035

3136
export interface TableObjectOptions extends TableObjectGetOptions {}
@@ -54,12 +59,22 @@ export class TableStore {
5459

5560
private reloadOnColChange = true;
5661
private reloadOnRowChange = true;
62+
private sortingTypeRows: SortingType;
63+
private sortingTypeColumns: SortingType;
5764

5865
// Flow actions
5966

6067
// Constructor
6168
constructor(opts: TableStoreConstructorOptions) {
62-
const { contextObject, subscriptionHandler, onSelectionChange, entriesLoader, validationMessages } = opts;
69+
const {
70+
contextObject,
71+
subscriptionHandler,
72+
onSelectionChange,
73+
entriesLoader,
74+
validationMessages,
75+
sortingTypeRows,
76+
sortingTypeColumns
77+
} = opts;
6378

6479
this.isLoading = false;
6580
this.contextObject = contextObject || null;
@@ -72,6 +87,9 @@ export class TableStore {
7287
this.entriesLoader = entriesLoader || ((_guids: TableGuids): void => {});
7388
this.validationMessages = validationMessages || [];
7489

90+
this.sortingTypeRows = sortingTypeRows || "none";
91+
this.sortingTypeColumns = sortingTypeColumns || "none";
92+
7593
if (entriesLoader) {
7694
when(
7795
() => {
@@ -354,13 +372,21 @@ export class TableStore {
354372

355373
@computed
356374
get tableColumns(): Array<ColumnProps<TableRecord>> {
357-
return this.columns.map(col => ({
375+
const columns = this.columns.map(col => ({
358376
key: col.id,
359377
dataIndex: col.id,
360378
guid: col.guid,
361379
title: col.title,
380+
sortKey: col._sortKey,
362381
className: col.className
363382
}));
383+
384+
if (this.sortingTypeColumns === "asc") {
385+
return sortBy(columns, "sortKey");
386+
} else if (this.sortingTypeColumns === "desc") {
387+
return sortBy(columns, "sortKey").reverse();
388+
}
389+
return columns;
364390
}
365391

366392
@computed
@@ -369,6 +395,7 @@ export class TableStore {
369395
const record: TableRecord = {
370396
key: row.guid,
371397
guid: row.guid,
398+
sortKey: row.sortKey,
372399
"row-title": row.title,
373400
_classObj: {},
374401
_className: row.className
@@ -399,7 +426,14 @@ export class TableStore {
399426
return record;
400427
});
401428

402-
const tree = arrayToTree(rows, arrayToTreeOpts);
429+
const tree = arrayToTree(
430+
this.sortingTypeRows === "none"
431+
? rows
432+
: this.sortingTypeRows === "asc"
433+
? sortBy(rows, "sortKey")
434+
: sortBy(rows, "sortKey").reverse(),
435+
arrayToTreeOpts
436+
);
403437
return tree.filter(treeEl => typeof treeEl._parent === "undefined" && !treeEl._parent);
404438
}
405439

typings/DynamicTableProps.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export type SelectionMode = "none" | "single" | "multi";
1212
export type ClickType = "single" | "double";
1313
export type SimpleAction = "nothing" | "microflow" | "nanoflow";
1414
export type FullAction = "nothing" | "microflow" | "nanoflow" | "open";
15+
export type SortingType = "asc" | "desc";
1516

1617
export namespace TableStyle {
1718
export type HeightUnitType = "percentageOfWidth" | "percentageOfParent" | "pixels";
@@ -52,6 +53,8 @@ interface DynamicTableRowProps {
5253
rowConstraint: string;
5354
rowGetDataMicroflow: string;
5455
rowGetDataNanoflow: Nanoflow;
56+
rowSortingAttribute: string;
57+
rowSortingOrder: SortingType;
5558
rowTitleType: TitleDataSourceType;
5659
rowTitleAttr: string;
5760
rowTitleNanoflow: Nanoflow;
@@ -74,6 +77,8 @@ interface DynamicTableColumnProps {
7477
columnConstraint: string;
7578
columnGetDataMicroflow: string;
7679
columnGetDataNanoflow: Nanoflow;
80+
columnSortingAttribute: string;
81+
columnSortingOrder: SortingType;
7782
columnTitleType: TitleDataSourceType;
7883
columnTitleAttr: string;
7984
columnTitleNanoflow: Nanoflow;

0 commit comments

Comments
 (0)