Skip to content

Commit 34b6aba

Browse files
Update: refactor jQuery implementation
1 parent 3167d23 commit 34b6aba

File tree

4 files changed

+168
-8
lines changed

4 files changed

+168
-8
lines changed

React/package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

React/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,20 @@
1515
},
1616
"dependencies": {
1717
"devextreme": "25.1.3",
18+
"devextreme-aspnet-data-nojquery": "^5.1.0",
1819
"devextreme-react": "25.1.3",
1920
"react": "^18.2.0",
2021
"react-dom": "^18.2.0"
2122
},
2223
"devDependencies": {
24+
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
2325
"@testing-library/jest-dom": "^5.16.5",
2426
"@testing-library/react": "^14.1.2",
2527
"@testing-library/user-event": "^14.4.3",
2628
"@types/react": "^18.2.47",
2729
"@types/react-dom": "^18.2.17",
2830
"@vitejs/plugin-react": "^4.4.1",
2931
"@vitest/coverage-v8": "^1.5.0",
30-
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
3132
"eslint": "^8.35.0",
3233
"eslint-config-devextreme": "^1.1.4",
3334
"eslint-plugin-no-only-tests": "2.6.0",
@@ -39,10 +40,10 @@
3940
"npm-run-all": "^4.1.5",
4041
"stylelint": "^15.6.1",
4142
"stylelint-config-standard": "^33.0.0",
43+
"ts-node": "10.9.2",
4244
"typescript": "~5.8.2",
4345
"typescript-eslint": "^8.18.2",
4446
"vite": "^6.3.5",
45-
"ts-node": "10.9.2",
4647
"vitest": "^1.5.0"
4748
}
48-
}
49+
}

React/src/Grid.tsx

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import { useState, useMemo, useCallback} from 'react';
2+
import DataGrid, { Column, RowDragging, Scrolling, Lookup, Selection } from 'devextreme-react/data-grid';
3+
import dxDataGrid, { RowDraggingStartEvent, Column as DxColumn, RowDraggingAddEvent, Row } from 'devextreme/ui/data_grid';
4+
import { DragTemplateData } from 'devextreme/ui/draggable';
5+
import CustomStore from 'devextreme/data/custom_store';
6+
import { Task, priorities } from './data';
7+
8+
interface GridDemoComponentProps {
9+
status?: number;
10+
tasksStore?: CustomStore;
11+
shouldClearSelection: boolean;
12+
}
13+
14+
function draggedItemsRender(data: DragTemplateData) {
15+
const draggedItems = data.itemData.map((item: Task, rowIndex: number) => {
16+
const cellValues = (Object.keys(item) as (keyof Task)[]).map((key: keyof Task, dataIndex: number) =>
17+
<td key={"key" + dataIndex}>{item[key]}</td>
18+
);
19+
return (<tr key={"row" + rowIndex}>{cellValues}</tr>)
20+
});
21+
return (<table className="drag-container">
22+
<tbody>{draggedItems}</tbody>
23+
</table>);
24+
}
25+
26+
function getVisibleRowValues(rowsData: Task[], grid: dxDataGrid) {
27+
const visibleColumns = grid.getVisibleColumns();
28+
const selectedData = rowsData.map((rowData: Task) => {
29+
const visibleValues: any = {};
30+
visibleColumns.forEach((column: DxColumn) => {
31+
if (column.dataField)
32+
visibleValues[column.dataField] = getVisibleCellValue(column, rowData);
33+
});
34+
return visibleValues;
35+
});
36+
return selectedData;
37+
}
38+
39+
function getVisibleCellValue(column: DxColumn, rowData: Task) {
40+
if (column.dataField) {
41+
const propKey = column.dataField as (keyof Task);
42+
const cellValue = rowData[propKey];
43+
return column.lookup && column.lookup.calculateCellValue ? column.lookup.calculateCellValue(cellValue) : cellValue;
44+
}
45+
}
46+
47+
export default function Grid({ status, tasksStore, shouldClearSelection }: GridDemoComponentProps) {
48+
const [updateInProgress, setUpdateInProgress] = useState(false);
49+
50+
const filterExpr = useMemo(() => {
51+
return ['Status', '=', status];
52+
}, [status]);
53+
54+
const dataSource = useMemo(() => {
55+
return {
56+
store: tasksStore,
57+
reshapeOnPush: true,
58+
};
59+
}, [tasksStore]);
60+
61+
const canDrag = useCallback((e: RowDraggingStartEvent) => {
62+
if (updateInProgress) return false;
63+
const visibleRows = e.component.getVisibleRows();
64+
return visibleRows.some((r: Row) => r.isSelected && r.rowIndex === e.fromIndex);
65+
}, [updateInProgress]);
66+
67+
const onDragStart = useCallback((e: RowDraggingStartEvent) => {
68+
const selectedData: Task[] = e.component.getSelectedRowsData();
69+
e.itemData = getVisibleRowValues(selectedData, e.component);
70+
e.cancel = !canDrag(e);
71+
}, [canDrag]);
72+
73+
const onAdd = useCallback((e: RowDraggingAddEvent) => {
74+
const fromGrid = e.fromComponent as dxDataGrid;
75+
const toGrid = e.toComponent as dxDataGrid;
76+
const selectedRowKeys: (keyof Task)[] = fromGrid.getSelectedRowKeys();
77+
const updateProcess: (Promise<any> | undefined)[] = [];
78+
const changes: any[] = [];
79+
80+
setUpdateInProgress(true);
81+
fromGrid.beginCustomLoading("Loading...");
82+
toGrid.beginCustomLoading("Loading...");
83+
for (let key of selectedRowKeys) {
84+
const values = { Status: e.toData };
85+
updateProcess.push(tasksStore?.update(key, values));
86+
changes.push({
87+
type: 'update',
88+
key,
89+
data: values,
90+
});
91+
}
92+
Promise.all(updateProcess).then(() => {
93+
tasksStore?.push(changes);
94+
fromGrid.endCustomLoading();
95+
toGrid.endCustomLoading();
96+
setUpdateInProgress(false);
97+
98+
fromGrid.clearSelection();
99+
if (!shouldClearSelection) {
100+
toGrid.selectRows(selectedRowKeys, true);
101+
}
102+
});
103+
}, [tasksStore, shouldClearSelection]);
104+
105+
return (
106+
<DataGrid
107+
dataSource={dataSource}
108+
height={440}
109+
showBorders={true}
110+
filterValue={filterExpr}
111+
>
112+
<RowDragging
113+
data={status}
114+
group="tasksGroup"
115+
onAdd={onAdd}
116+
onDragStart={onDragStart}
117+
dragRender={draggedItemsRender}
118+
/>
119+
<Selection mode="multiple" />
120+
<Scrolling mode="virtual" />
121+
<Column
122+
dataField="Subject"
123+
dataType="string"
124+
/>
125+
<Column
126+
dataField="Priority"
127+
dataType="number"
128+
width={80}
129+
>
130+
<Lookup
131+
dataSource={priorities}
132+
valueExpr="id"
133+
displayExpr="text"
134+
/>
135+
</Column>
136+
<Column
137+
dataField="Status"
138+
dataType="number"
139+
visible={false}
140+
/>
141+
142+
</DataGrid>
143+
);
144+
};

jQuery/src/index.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,18 +112,23 @@ $(() => {
112112

113113
function getVisibleRowValues(rowsData, grid) {
114114
const visibleColumns = grid.getVisibleColumns().filter((c) => c.dataField);
115-
const selectedData = rowsData.map((s) => {
115+
const selectedData = rowsData.map((rowData) => {
116116
const visibleValues = {};
117117
visibleColumns.forEach((column) => {
118-
visibleValues[column.dataField] = column.lookup
119-
? column.lookup.calculateCellValue(s[column.dataField])
120-
: s[column.dataField];
118+
if(column.dataField){
119+
visibleValues[column.dataField] = getVisibleCellValue(column, rowData);
120+
}
121121
});
122-
return visibleValues;
122+
return visibleValues;
123123
});
124124
return selectedData;
125125
}
126126

127+
function getVisibleCellValue(column, rowData){
128+
const cellValue = rowData[column.dataField];
129+
return column.lookup ? column.lookup.calculateCellValue(cellValue) : cellValue;
130+
}
131+
127132
function shouldClearSelection() {
128133
return $('#clear-after-drop-switch').dxSwitch('option', 'value');
129134
}

0 commit comments

Comments
 (0)