Skip to content

Commit 3167d23

Browse files
Fix: Angular implementation, lint, and build issues
1 parent ab76159 commit 3167d23

16 files changed

+240
-304
lines changed

Angular/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.

Angular/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
"build": "ng build",
88
"watch": "ng build --watch --configuration development",
99
"test": "ng test",
10-
"lint-html": "prettier --check .",
11-
"lint-ts": "eslint --ext .ts .",
12-
"lint-css": "stylelint src/**/*.{css,scss} --allow-empty-input",
10+
"lint-html": "prettier --write .",
11+
"lint-ts": "eslint --ext .ts . --fix",
12+
"lint-css": "stylelint src/**/*.{css,scss} --allow-empty-input --fix",
1313
"lint": "npm-run-all -p -c lint-ts lint-css lint-html"
1414
},
1515
"private": true,
@@ -24,6 +24,7 @@
2424
"@angular/router": "^18.0.3",
2525
"devextreme": "25.1.3",
2626
"devextreme-angular": "25.1.3",
27+
"devextreme-aspnet-data-nojquery": "^5.1.0",
2728
"rxjs": "~7.8.0",
2829
"tslib": "^2.3.0",
2930
"zone.js": "~0.14.7"

Angular/src/app/app.component.html

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,62 @@
11
<div class="default-style">
2-
<dx-button [text]="buttonText" (onClick)="onClick($event)"></dx-button>
2+
<div class="demo-header">
3+
<h3>DataGrid - Select multiple items and drag'n'drop between grids</h3>
4+
<div id="toggle-container">
5+
<span>Clear selection of dropped items</span>
6+
<dx-switch [(value)]="shouldClearSelection"></dx-switch>
7+
</div>
8+
</div>
9+
<div class="tables">
10+
<div *ngFor="let status of statuses" class="column">
11+
<dx-data-grid
12+
[dataSource]="dataSource"
13+
[height]="440"
14+
[showBorders]="true"
15+
[filterValue]="['Status', '=', status]"
16+
>
17+
<dxo-data-grid-row-dragging
18+
[data]="status"
19+
group="tasksGroup"
20+
[onAdd]="onAdd"
21+
[onDragStart]="onDragStart"
22+
dragTemplate="drag-template"
23+
></dxo-data-grid-row-dragging>
24+
25+
<div *dxTemplate="let dragData of 'drag-template'">
26+
<table class="drag-container">
27+
<tr *ngFor="let rowData of dragData.itemData">
28+
<td *ngFor="let field of rowData | keyvalue : originalOrder">{{
29+
field.value
30+
}}</td>
31+
</tr>
32+
</table>
33+
</div>
34+
35+
<dxo-selection mode="multiple"></dxo-selection>
36+
37+
<dxo-scrolling mode="virtual"></dxo-scrolling>
38+
39+
<dxi-data-grid-column
40+
dataField="Subject"
41+
dataType="string"
42+
></dxi-data-grid-column>
43+
<dxi-data-grid-column
44+
dataField="Priority"
45+
dataType="number"
46+
[width]="80"
47+
>
48+
<dxo-lookup
49+
[dataSource]="priorities"
50+
valueExpr="id"
51+
displayExpr="text"
52+
></dxo-lookup>
53+
</dxi-data-grid-column>
54+
<dxi-data-grid-column
55+
dataField="Status"
56+
dataType="number"
57+
[visible]="false"
58+
></dxi-data-grid-column>
59+
</dx-data-grid>
60+
</div>
61+
</div>
362
</div>

Angular/src/app/app.component.scss

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,43 @@
11
.default-style {
22
margin: 50px;
3-
width: 90vw;
3+
width: 90vh;
44
}
5+
6+
.demo-header {
7+
display: flex;
8+
justify-content: space-between;
9+
}
10+
11+
#toggle-container {
12+
padding-top: 20px;
13+
}
14+
15+
#clear-after-drop-switch {
16+
vertical-align: text-bottom;
17+
}
18+
19+
#toggle-container span {
20+
padding-right: 10px;
21+
}
22+
23+
.drag-container {
24+
padding: 10px;
25+
}
26+
27+
.drag-container td {
28+
padding: 0 10px;
29+
}
30+
31+
.tables {
32+
display: flex;
33+
}
34+
35+
.column:first-child {
36+
width: 50%;
37+
padding-right: 15px;
38+
}
39+
40+
.column:last-child {
41+
width: 50%;
42+
padding-left: 15px;
43+
}

Angular/src/app/app.component.ts

Lines changed: 120 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,133 @@
11
import { Component } from '@angular/core';
2-
import { ClickEvent } from 'devextreme/ui/button';
2+
import { KeyValue } from '@angular/common';
3+
import { Task, Priority, GridDataService } from 'src/app/services/grid-data.service';
4+
import * as AspNetData from 'devextreme-aspnet-data-nojquery';
5+
import DxDataGrid, {
6+
RowDraggingStartEvent, RowDraggingAddEvent, Column, Row,
7+
} from 'devextreme/ui/data_grid';
8+
import CustomStore from 'devextreme/data/custom_store';
9+
import { DataSourceOptions } from 'devextreme/data/data_source';
10+
import notify from 'devextreme/ui/notify';
311

412
@Component({
513
selector: 'app-root',
614
templateUrl: './app.component.html',
715
styleUrls: ['./app.component.scss'],
816
})
917
export class AppComponent {
10-
title = 'Angular';
18+
statuses: number[];
1119

12-
counter = 0;
20+
priorities: Priority[];
1321

14-
buttonText = 'Click count: 0';
22+
tasksStore: CustomStore;
1523

16-
onClick(e: ClickEvent): void {
17-
this.counter++;
18-
this.buttonText = `Click count: ${this.counter}`;
24+
dataSource: DataSourceOptions;
25+
26+
shouldClearSelection = false;
27+
28+
updateInProgress: Boolean = false;
29+
30+
constructor(service: GridDataService) {
31+
const url = 'https://js.devexpress.com/Demos/Mvc/api/DnDBetweenGrids';
32+
33+
this.priorities = service.getPriorities();
34+
this.statuses = [1, 2];
35+
this.tasksStore = AspNetData.createStore({
36+
key: 'ID',
37+
loadUrl: `${url}/Tasks`,
38+
updateUrl: `${url}/UpdateTask`,
39+
onBeforeSend(method, ajaxOptions) {
40+
ajaxOptions.xhrFields = { withCredentials: true };
41+
},
42+
});
43+
this.dataSource = {
44+
store: this.tasksStore,
45+
reshapeOnPush: true,
46+
};
47+
48+
this.onDragStart = this.onDragStart.bind(this);
49+
this.onAdd = this.onAdd.bind(this);
50+
this.canDrag = this.canDrag.bind(this);
51+
}
52+
53+
onDragStart(e: any): void {
54+
const selectedData: Task[] = e.component.getSelectedRowsData();
55+
e.itemData = this.getVisibleRowValues(selectedData, e.component);
56+
e.cancel = !this.canDrag(e);
57+
}
58+
59+
async onAdd(e: any): Promise<void> {
60+
const fromGrid = e.fromComponent as DxDataGrid;
61+
const toGrid = e.toComponent as DxDataGrid;
62+
const selectedRowKeys: (keyof Task)[] = fromGrid.getSelectedRowKeys();
63+
const updateProcess: Promise<any>[] = [];
64+
const changes: any[] = [];
65+
66+
this.updateInProgress = true;
67+
fromGrid.beginCustomLoading('Loading...');
68+
toGrid.beginCustomLoading('Loading...');
69+
70+
for (let key of selectedRowKeys) {
71+
const values: Task = { Status: e.toData };
72+
73+
updateProcess.push(this.tasksStore.update(key, values));
74+
changes.push({
75+
type: 'update',
76+
key,
77+
data: values,
78+
});
79+
}
80+
81+
try {
82+
await Promise.all(updateProcess);
83+
84+
this.tasksStore.push(changes);
85+
fromGrid.endCustomLoading();
86+
toGrid.endCustomLoading();
87+
this.updateInProgress = false;
88+
89+
fromGrid.clearSelection();
90+
if (!this.shouldClearSelection) {
91+
await toGrid.selectRows(selectedRowKeys, true);
92+
}
93+
} catch {
94+
notify('An error occurred while saving changes.', 'error', 3000);
95+
}
96+
}
97+
98+
getVisibleRowValues(rowsData: Task[], grid: DxDataGrid): Record<string, Task[keyof Task] | string | undefined>[] {
99+
const visibleColumns = grid.getVisibleColumns();
100+
const selectedData = rowsData.map((rowData: Task) => {
101+
const visibleValues: Record<string, Task[keyof Task] | string | undefined> = {};
102+
visibleColumns.forEach((column: Column) => {
103+
if (column.dataField) {
104+
visibleValues[column.dataField] = this.getVisibleCellValue(column, rowData);
105+
}
106+
});
107+
return visibleValues;
108+
});
109+
return selectedData;
110+
}
111+
112+
getVisibleCellValue(column: Column, rowData: Task): Task[keyof Task] | string | undefined {
113+
if (column.dataField) {
114+
const propKey = column.dataField as keyof Task;
115+
const cellValue = rowData[propKey];
116+
117+
return column.lookup?.calculateCellValue
118+
? String(column.lookup.calculateCellValue(cellValue))
119+
: cellValue;
120+
}
121+
return undefined;
122+
}
123+
124+
canDrag(e: RowDraggingStartEvent): Row | Boolean {
125+
if (this.updateInProgress) return false;
126+
const visibleRows = e.component.getVisibleRows();
127+
return visibleRows.some((r: Row) => r.isSelected && r.rowIndex === e.fromIndex);
128+
}
129+
130+
originalOrder(a: KeyValue<number, string>, b: KeyValue<number, string>): number {
131+
return 0;
19132
}
20133
}

Angular/src/app/app.module.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { NgModule } from '@angular/core';
22
import { BrowserModule } from '@angular/platform-browser';
3-
import { DxButtonModule } from 'devextreme-angular/ui/button';
3+
import { DxDataGridModule, DxSwitchModule } from 'devextreme-angular';
44
import { AppRoutingModule } from './app-routing.module';
55
import { AppComponent } from './app.component';
66

@@ -11,7 +11,8 @@ import { AppComponent } from './app.component';
1111
imports: [
1212
BrowserModule,
1313
AppRoutingModule,
14-
DxButtonModule,
14+
DxDataGridModule,
15+
DxSwitchModule,
1516
],
1617
providers: [],
1718
bootstrap: [AppComponent],

Angular/src/app/orig_app-routing.module.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.

Angular/src/app/orig_app.component.html

Lines changed: 0 additions & 53 deletions
This file was deleted.

0 commit comments

Comments
 (0)