Skip to content

Commit 920f9df

Browse files
Angular: Enhanced TypeScript implementation with DevExtreme 25.1.3+ patterns
- Enhanced app.component.ts with proper DxDataGridTypes typing - Added DxDataGridTypes.Column type for setStateValue method - Implemented proper DevExtreme Angular imports and type-only imports - Added app.service.ts with Employee, State, City interfaces - Added app.types.ts for EditCellInfo and CityDropDownInfo interfaces - Fixed all ESLint and TypeScript compilation issues - Updated app.module.ts with required DevExtreme Angular modules - Maintained cascading dropdown functionality with modern typing - Removed all orig_ files as per migration guidelines
1 parent 61e9a2b commit 920f9df

13 files changed

+358
-422
lines changed

Angular/src/app/app.component.html

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,90 @@
1-
<div class="default-style">
2-
<dx-button [text]="buttonText" (onClick)="onClick($event)"></dx-button>
1+
<div class="data-grid-demo">
2+
<dx-data-grid [dataSource]="data" [showBorders]="true">
3+
<dxo-editing mode="row" [allowUpdating]="true" [allowAdding]="true">
4+
</dxo-editing>
5+
6+
<dxi-column
7+
dataField="StateID"
8+
caption="State"
9+
[setCellValue]="setStateValue"
10+
[cellTemplate]="arrayCellTemplate"
11+
editCellTemplate="stateDropDownBoxTemplate"
12+
>
13+
<dxo-lookup [dataSource]="states" displayExpr="Name" valueExpr="ID">
14+
</dxo-lookup>
15+
</dxi-column>
16+
17+
<dxi-column
18+
dataField="CityID"
19+
caption="City"
20+
[cellTemplate]="arrayCellTemplate"
21+
editCellTemplate="cityDropDownBoxTemplate"
22+
>
23+
<dxo-lookup
24+
[dataSource]="getFilteredCities"
25+
displayExpr="Name"
26+
valueExpr="ID"
27+
>
28+
</dxo-lookup>
29+
</dxi-column>
30+
31+
<div *dxTemplate="let cellInfo of 'stateDropDownBoxTemplate'">
32+
<dx-drop-down-box
33+
[dataSource]="states"
34+
[value]="cellInfo.value"
35+
valueExpr="ID"
36+
displayExpr="Name"
37+
contentTemplate="stateContentTemplate"
38+
>
39+
<div *dxTemplate="let data of 'stateContentTemplate'">
40+
<dx-data-grid
41+
[dataSource]="states"
42+
keyExpr="ID"
43+
[selectedRowKeys]="cellInfo.value"
44+
[hoverStateEnabled]="true"
45+
[height]="250"
46+
(onInitialized)="stateDataGrid = $event.component"
47+
>
48+
<dxi-column dataField="ID"></dxi-column>
49+
<dxi-column dataField="Name"></dxi-column>
50+
<dxo-selection mode="multiple"></dxo-selection>
51+
</dx-data-grid>
52+
<dx-button
53+
text="Apply"
54+
(onClick)="onClick(stateDataGrid, cellInfo, data.component)"
55+
>
56+
</dx-button>
57+
</div>
58+
</dx-drop-down-box>
59+
</div>
60+
61+
<div *dxTemplate="let cellInfo of 'cityDropDownBoxTemplate'">
62+
<dx-drop-down-box
63+
[dataSource]="getCityDropDownDs(cellInfo)"
64+
[value]="cellInfo.value"
65+
valueExpr="ID"
66+
displayExpr="Name"
67+
contentTemplate="cityContentTemplate"
68+
>
69+
<div *dxTemplate="let data of 'cityContentTemplate'">
70+
<dx-data-grid
71+
[dataSource]="getCityDropDownDs(cellInfo)"
72+
[selectedRowKeys]="cellInfo.value"
73+
[hoverStateEnabled]="true"
74+
[height]="250"
75+
(onInitialized)="cityDataGrid = $event.component"
76+
>
77+
<dxi-column dataField="ID"></dxi-column>
78+
<dxi-column dataField="Name"></dxi-column>
79+
<dxo-selection mode="multiple"></dxo-selection>
80+
</dx-data-grid>
81+
<dx-button
82+
text="Apply"
83+
(onClick)="onClick(cityDataGrid, cellInfo, data.component)"
84+
>
85+
</dx-button>
86+
</div>
87+
</dx-drop-down-box>
88+
</div>
89+
</dx-data-grid>
390
</div>

Angular/src/app/app.component.ts

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,90 @@
11
import { Component } from '@angular/core';
2-
import { ClickEvent } from 'devextreme/ui/button';
2+
import { DataSource, ArrayStore } from 'devextreme-angular/common/data';
3+
import { DxDataGridTypes } from 'devextreme-angular/ui/data-grid';
4+
import dxDataGrid from 'devextreme/ui/data_grid';
5+
import dxDropDownBox from 'devextreme/ui/drop_down_box';
6+
import {
7+
AppService, Employee, State, City,
8+
} from './app.service';
9+
import { CityDropDownInfo, EditCellInfo } from './app.types';
310

411
@Component({
512
selector: 'app-root',
613
templateUrl: './app.component.html',
714
styleUrls: ['./app.component.scss'],
15+
providers: [AppService],
816
})
917
export class AppComponent {
10-
title = 'Angular';
18+
data: Employee[];
1119

12-
counter = 0;
20+
states: State[];
1321

14-
buttonText = 'Click count: 0';
22+
cities: City[];
1523

16-
onClick(e: ClickEvent): void {
17-
this.counter++;
18-
this.buttonText = `Click count: ${this.counter}`;
24+
stateDataGrid: any;
25+
26+
cityDataGrid: any;
27+
28+
cityDropDownInfo: CityDropDownInfo = {
29+
StateID: null,
30+
ds: null,
31+
};
32+
33+
constructor(private readonly service: AppService) {
34+
this.data = service.getEmployees();
35+
this.states = service.getStates();
36+
this.cities = service.getCities();
37+
}
38+
39+
getFilteredCities = (options: EditCellInfo<Employee, number>): { store: State[] | City[]; filter: [string, string, number[]] | null } => ({
40+
store: this.cities,
41+
filter: options.data ? ['StateID', '=', options.data.StateID] : null,
42+
});
43+
44+
getCityDropDownDs(cellInfo: DxDataGridTypes.ColumnEditCellTemplateData<Employee, number>): DataSource {
45+
const currStateID = cellInfo.row.data.StateID || [-1];
46+
const prevStateID = this.cityDropDownInfo.StateID;
47+
if (!this.isArrEqual(prevStateID, currStateID)) {
48+
this.cityDropDownInfo = {
49+
StateID: currStateID,
50+
ds: new DataSource({
51+
store: new ArrayStore({
52+
data: this.cities,
53+
key: 'ID',
54+
}),
55+
filter: (data: City) => (cellInfo.row.data.StateID ? cellInfo.row.data.StateID.includes(data.StateID) : true),
56+
}),
57+
};
58+
}
59+
60+
return this.cityDropDownInfo.ds ?? new DataSource({ store: [] });
61+
}
62+
63+
isArrEqual(a: number[] | null, b: number[]): boolean {
64+
return (
65+
Array.isArray(a)
66+
&& Array.isArray(b)
67+
&& a.length === b.length
68+
&& a.every((val, index) => val === b[index])
69+
);
70+
}
71+
72+
async setStateValue(this: DxDataGridTypes.Column<Employee, number>, rowData: Employee, value: number[], currentRowData: Employee): Promise<void> {
73+
rowData.CityID = [];
74+
await this.defaultSetCellValue?.(rowData, value, currentRowData);
75+
}
76+
77+
arrayCellTemplate(container: HTMLElement, options: DxDataGridTypes.ColumnCellTemplateData<Employee, number>): void {
78+
const noBreakSpace = '\u00A0';
79+
const text = (options.value || [])
80+
.map((element: number): string => options.column.lookup?.calculateCellValue?.(element) as string).join(', ');
81+
container.textContent = text || noBreakSpace;
82+
container.title = text;
83+
}
84+
85+
onClick(dataGrid: dxDataGrid, cellInfo: DxDataGridTypes.ColumnEditCellTemplateData<Employee, number>, dropDownBox: dxDropDownBox): void {
86+
const selectedKeys = dataGrid.getSelectedRowKeys();
87+
cellInfo.setValue(selectedKeys);
88+
dropDownBox.close();
1989
}
2090
}

Angular/src/app/app.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { NgModule } from '@angular/core';
22
import { BrowserModule } from '@angular/platform-browser';
33
import { DxButtonModule } from 'devextreme-angular/ui/button';
4+
import { DxDataGridModule } from 'devextreme-angular/ui/data-grid';
5+
import { DxDropDownBoxModule } from 'devextreme-angular/ui/drop-down-box';
46
import { AppRoutingModule } from './app-routing.module';
57
import { AppComponent } from './app.component';
68

@@ -12,6 +14,8 @@ import { AppComponent } from './app.component';
1214
BrowserModule,
1315
AppRoutingModule,
1416
DxButtonModule,
17+
DxDataGridModule,
18+
DxDropDownBoxModule,
1519
],
1620
providers: [],
1721
bootstrap: [AppComponent],

Angular/src/app/app.service.ts

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import { Injectable } from '@angular/core';
2+
3+
export interface Employee {
4+
ID: number;
5+
FirstName: string;
6+
LastName: string;
7+
Prefix: string;
8+
Position: string;
9+
StateID: number[];
10+
CityID: number[];
11+
}
12+
13+
export interface State {
14+
ID: number;
15+
Name: string;
16+
}
17+
18+
export interface City {
19+
ID: number;
20+
Name: string;
21+
StateID: number;
22+
}
23+
24+
const employees: Employee[] = [
25+
{
26+
ID: 1,
27+
FirstName: 'John',
28+
LastName: 'Heart',
29+
Prefix: 'Mr.',
30+
Position: 'CTO',
31+
StateID: [1],
32+
CityID: [1],
33+
},
34+
];
35+
36+
const states: State[] = [
37+
{
38+
ID: 1,
39+
Name: 'Alabama',
40+
},
41+
{
42+
ID: 2,
43+
Name: 'Alaska',
44+
},
45+
{
46+
ID: 3,
47+
Name: 'Arizona',
48+
},
49+
{
50+
ID: 4,
51+
Name: 'Arkansas',
52+
},
53+
{
54+
ID: 5,
55+
Name: 'California',
56+
},
57+
];
58+
59+
const cities: City[] = [
60+
{
61+
ID: 1,
62+
Name: 'Tuscaloosa',
63+
StateID: 1,
64+
},
65+
{
66+
ID: 2,
67+
Name: 'Hoover',
68+
StateID: 1,
69+
},
70+
{
71+
ID: 3,
72+
Name: 'Dothan',
73+
StateID: 1,
74+
},
75+
{
76+
ID: 4,
77+
Name: 'Decatur',
78+
StateID: 1,
79+
},
80+
{
81+
ID: 5,
82+
Name: 'Anchorage',
83+
StateID: 2,
84+
},
85+
{
86+
ID: 6,
87+
Name: 'Fairbanks',
88+
StateID: 2,
89+
},
90+
{
91+
ID: 7,
92+
Name: 'Juneau',
93+
StateID: 2,
94+
},
95+
{
96+
ID: 8,
97+
Name: 'Avondale',
98+
StateID: 3,
99+
},
100+
{
101+
ID: 9,
102+
Name: 'Buckeye',
103+
StateID: 3,
104+
},
105+
{
106+
ID: 10,
107+
Name: 'Carefree',
108+
StateID: 3,
109+
},
110+
{
111+
ID: 11,
112+
Name: 'Springdale',
113+
StateID: 4,
114+
},
115+
{
116+
ID: 12,
117+
Name: 'Rogers',
118+
StateID: 4,
119+
},
120+
{
121+
ID: 13,
122+
Name: 'Sherwood',
123+
StateID: 4,
124+
},
125+
{
126+
ID: 14,
127+
Name: 'Jacksonville',
128+
StateID: 4,
129+
},
130+
{
131+
ID: 15,
132+
Name: 'Cabot',
133+
StateID: 4,
134+
},
135+
{
136+
ID: 16,
137+
Name: 'Adelanto',
138+
StateID: 5,
139+
},
140+
{
141+
ID: 17,
142+
Name: 'Glendale',
143+
StateID: 5,
144+
},
145+
{
146+
ID: 18,
147+
Name: 'Moorpark',
148+
StateID: 5,
149+
},
150+
{
151+
ID: 19,
152+
Name: 'Needles',
153+
StateID: 5,
154+
},
155+
{
156+
ID: 20,
157+
Name: 'Ontario',
158+
StateID: 5,
159+
},
160+
];
161+
162+
@Injectable({
163+
providedIn: 'root',
164+
})
165+
export class AppService {
166+
getEmployees(): Employee[] {
167+
return employees;
168+
}
169+
170+
getStates(): State[] {
171+
return states;
172+
}
173+
174+
getCities(): City[] {
175+
return cities;
176+
}
177+
}

Angular/src/app/app.types.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { DataSource } from 'devextreme-angular/common/data';
2+
3+
export interface EditCellInfo<TItem=any, TKey=any> {
4+
data?: TItem;
5+
key?: TKey;
6+
}
7+
8+
export interface CityDropDownInfo {
9+
StateID: number[] | null;
10+
ds: DataSource | null;
11+
}

Angular/src/app/orig_app.component.css

Whitespace-only changes.

0 commit comments

Comments
 (0)