Skip to content

Commit 0ae4d93

Browse files
Update to 25.1.3+
1 parent 1076aad commit 0ae4d93

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+17422
-27
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Mvc;
6+
7+
namespace ASP_NET_Core.Controllers
8+
{
9+
public class HomeController : Controller
10+
{
11+
public IActionResult Index()
12+
{
13+
return View();
14+
}
15+
16+
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
17+
public IActionResult Error() {
18+
return View();
19+
}
20+
}
21+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
@using ASP_NET_Core.Models
2+
3+
@{
4+
string url = "https://js.devexpress.com/Demos/Mvc/api/DataGridWebApi";
5+
}
6+
7+
@(Html.DevExtreme().DataGrid()
8+
.OnInitialized("(e) => { new GroupSelectionBehavior(e.component); }")
9+
.Selection(s => s.Mode(SelectionMode.Multiple).AllowSelectAll(true).ShowCheckBoxesMode(GridSelectionShowCheckBoxesMode.Always))
10+
.SelectedRowKeys(new JS("[10521]"))
11+
.Height(800)
12+
.Width(1200)
13+
.ShowBorders(true)
14+
.DataSource(d => d.RemoteController().LoadUrl(url + "/Orders").Key("OrderID"))
15+
.Columns(columns => {
16+
columns.Add().DataField("OrderID");
17+
columns.Add().DataField("CustomerID").Caption("Customer")
18+
.Lookup(lk => lk
19+
.ValueExpr("Value")
20+
.DisplayExpr("Text")
21+
.DataSource(d => d.RemoteController()
22+
.LoadUrl(url + "/CustomersLookup")
23+
.Key("Value"))
24+
);
25+
columns.Add().DataField("OrderDate").DataType(GridColumnDataType.Date);
26+
columns.Add().DataField("Freight");
27+
columns.Add().DataField("ShipCountry").GroupIndex(0);
28+
columns.Add().DataField("ShipCity").GroupIndex(2);
29+
columns.Add().DataField("ShipVia").GroupIndex(1)
30+
.Lookup(lk => lk
31+
.ValueExpr("Value")
32+
.DisplayExpr("Text")
33+
.DataSource(d => d.RemoteController()
34+
.LoadUrl(url + "/ShippersLookup")
35+
.Key("Value"))
36+
);
37+
})
38+
.GroupPanel(p => p.Visible(true))
39+
.Grouping(g => g.AutoExpandAll(false))
40+
.RemoteOperations(true)
41+
)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
3+
<html>
4+
<head>
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<meta charset="utf-8">
7+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
8+
<meta name="description" content="">
9+
<meta name="author" content="">
10+
11+
<title>ASP_NET_Core</title>
12+
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
13+
14+
@* Uncomment to use the HtmlEditor control *@
15+
@* <script src="https://unpkg.com/devextreme-quill/dist/dx-quill.min.js"></script> *@
16+
17+
<link rel="stylesheet" href="~/css/vendor.css" asp-append-version="true" />
18+
<link rel="stylesheet" href="~/css/Site.css" />
19+
<script src="~/js/vendor.js" asp-append-version="true"></script>
20+
<script src="~/js/GroupSelectionBehavior.js" asp-append-version="true"></script>
21+
</head>
22+
23+
<body class="dx-viewport">
24+
<div class="demo-container">
25+
@RenderBody()
26+
</div>
27+
</body>
28+
29+
</html>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.group-selection-front {
2+
margin-right: 10px;
3+
}
4+
5+
.group-selection-front .dx-loadindicator {
6+
display: block;
7+
}
8+
9+
.group-row-flex {
10+
display: flex;
11+
flex-direction: row;
12+
align-items: center;
13+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<div class="group-row-flex">
2+
<div class="group-selection-front">
3+
<dx-load-indicator
4+
[height]="iconSize"
5+
[width]="iconSize"
6+
[visible]="isLoading"
7+
></dx-load-indicator>
8+
<dx-check-box
9+
*ngIf="!isLoading"
10+
[iconSize]="iconSize"
11+
[value]="checked"
12+
(onValueChanged)="checkBoxValueChanged($event)"
13+
></dx-check-box>
14+
</div>
15+
<span>{{ groupCellData | groupText }}</span>
16+
</div>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import {
2+
Component, Input, Output, EventEmitter, AfterViewInit,
3+
} from '@angular/core';
4+
import { DxCheckBoxTypes } from 'devextreme-angular/ui/check-box';
5+
import { DxDataGridTypes } from 'devextreme-angular/ui/data-grid';
6+
7+
@Component({
8+
selector: 'group-row-selectable',
9+
templateUrl: './group-row.component.html',
10+
styleUrls: ['./group-row.component.css'],
11+
})
12+
export class GroupRowComponent implements AfterViewInit {
13+
@Input() groupCellData!: DxDataGridTypes.ColumnGroupCellTemplateData;
14+
15+
@Input() childRowKeys: any[] | undefined = [];
16+
17+
@Output() onInitialized = new EventEmitter<IGroupRowReadyParameter>();
18+
19+
isLoading = true;
20+
21+
checked: boolean | undefined = false;
22+
23+
childKeys!: any[];
24+
25+
iconSize = 18;
26+
27+
constructor() {
28+
this.checkBoxValueChanged = this.checkBoxValueChanged.bind(this);
29+
}
30+
31+
ngAfterViewInit(): void {
32+
this.onInitialized.emit({ key: this.groupCellData.row.key, component: this });
33+
}
34+
35+
checkBoxValueChanged(e: DxCheckBoxTypes.ValueChangedEvent): void {
36+
this.checked = e.value;
37+
if (e.value) {
38+
this.groupCellData.component.selectRows(this.childRowKeys ?? [], true).catch(() => {});
39+
} else {
40+
this.groupCellData.component.deselectRows(this.childRowKeys ?? []).catch(() => {});
41+
}
42+
}
43+
44+
public setCheckedState(value: boolean | undefined): void {
45+
this.checked = value;
46+
this.isLoading = false;
47+
}
48+
}
49+
export interface IGroupRowReadyParameter {
50+
key: string[];
51+
component: GroupRowComponent;
52+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import dxDataGrid from 'devextreme/ui/data_grid';
2+
import { DxDataGridTypes } from 'devextreme-angular/ui/data-grid';
3+
import { LoadOptions } from 'devextreme/data';
4+
import { isItemsArray } from 'devextreme/common/data/custom-store';
5+
import { IGroupRowReadyParameter } from './group-row-component/group-row.component';
6+
7+
export default class GroupSelectionHelper {
8+
groupedColumns: DxDataGridTypes.Column[];
9+
10+
grid: dxDataGrid;
11+
12+
getSelectedKeysPromise: Promise<any[]> | null;
13+
14+
selectedKeys: any[] = [];
15+
16+
groupChildKeys: Record<string, any> = {};
17+
18+
constructor(grid: dxDataGrid) {
19+
this.grid = grid;
20+
this.groupedColumns = this.collectGroupedColumns(grid);
21+
this.getSelectedKeysPromise = this.getSelectedKeys(grid);
22+
this.getSelectedKeysPromise.then((keys: any[]) => {
23+
this.selectedKeys = keys;
24+
}).catch(() => {});
25+
const defaultCustomizeCallback: Function | undefined = grid.option('customizeColumns');
26+
grid.option('customizeColumns', (columns: DxDataGridTypes.Column[]) => {
27+
columns.forEach((column: DxDataGridTypes.Column) => {
28+
column.groupCellTemplate = 'groupCellTemplate';
29+
});
30+
if (defaultCustomizeCallback) { defaultCustomizeCallback(columns); }
31+
});
32+
const defaultSelectionHandler: Function | undefined = grid.option('onSelectionChanged');
33+
grid.option('onSelectionChanged', (e: DxDataGridTypes.SelectionChangedEvent) => {
34+
this.selectionChanged(e);
35+
if (defaultSelectionHandler) { defaultSelectionHandler(e); }
36+
});
37+
const defaultOptionChangedHandler: Function | undefined = grid.option('onOptionChanged');
38+
grid.option('onOptionChanged', (e: DxDataGridTypes.OptionChangedEvent) => {
39+
if (e.fullName.includes('groupIndex')) {
40+
this.groupedColumns = this.collectGroupedColumns(grid);
41+
}
42+
if (defaultOptionChangedHandler) { defaultOptionChangedHandler(e); }
43+
});
44+
}
45+
46+
groupRowInit(arg: IGroupRowReadyParameter): void {
47+
const checkBoxId = this.calcCheckBoxId(this.grid, arg.key);
48+
if (!this.groupChildKeys[checkBoxId]) {
49+
const filter: any[] = [];
50+
arg.key.forEach((key, i) => {
51+
filter.push([this.groupedColumns[i].dataField, '=', key]);
52+
});
53+
const loadOptions: LoadOptions = {
54+
filter,
55+
};
56+
const store = this.grid.getDataSource().store();
57+
store.load(loadOptions).then((data) => {
58+
if (isItemsArray(data)) {
59+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
60+
this.groupChildKeys[checkBoxId] = data.map((d) => this.grid.keyOf(d));
61+
this.getSelectedKeys(this.grid).then((selectedKeys) => {
62+
const checkedState: boolean | undefined = this.areKeysSelected(this.groupChildKeys[checkBoxId], selectedKeys);
63+
arg.component.setCheckedState(checkedState);
64+
}).catch(() => {});
65+
}
66+
}).catch(() => {});
67+
} else {
68+
this.getSelectedKeys(this.grid).then((selectedKeys) => {
69+
const checkedState: boolean | undefined = this.areKeysSelected(this.groupChildKeys[checkBoxId], selectedKeys);
70+
arg.component.setCheckedState(checkedState);
71+
}).catch(() => {});
72+
}
73+
}
74+
75+
selectionChanged(e: DxDataGridTypes.SelectionChangedEvent): void {
76+
const groupRows: DxDataGridTypes.Row[] = e.component.getVisibleRows().filter((r) => r.rowType === 'group');
77+
this.getSelectedKeysPromise = null;
78+
if (e.component.option('selection.deferred')) {
79+
const selectionFilter = e.component.option('selectionFilter');
80+
if (selectionFilter && selectionFilter.length >= 0) {
81+
this.repaintGroupRowTree(e.component, groupRows);
82+
} else {
83+
e.component.repaintRows(groupRows.map((g) => g.rowIndex));
84+
}
85+
} else if (e.selectedRowKeys.length >= e.component.totalCount() || e.currentDeselectedRowKeys.length >= e.component.totalCount()) {
86+
e.component.repaintRows(groupRows.map((g) => g.rowIndex));
87+
} else {
88+
this.repaintGroupRowTree(e.component, groupRows);
89+
}
90+
}
91+
92+
getSelectedKeys(grid: dxDataGrid): Promise<any[]> {
93+
if (grid.option('selection.deferred')) {
94+
if (!this.getSelectedKeysPromise) {
95+
this.getSelectedKeysPromise = grid.getSelectedRowKeys();
96+
}
97+
return this.getSelectedKeysPromise;
98+
}
99+
return Promise.resolve(grid.getSelectedRowKeys());
100+
}
101+
102+
repaintGroupRowTree(grid: dxDataGrid, groupRows: DxDataGridTypes.Row[]): void {
103+
const topGroupRow: DxDataGridTypes.Row | null = groupRows.filter((r) => r.isExpanded).reduce((acc: DxDataGridTypes.Row | null, curr) => (!acc || acc.key.length > curr.key.length ? curr : acc), null);
104+
if (topGroupRow) {
105+
const affectedGroupRows = groupRows.filter((g) => g.key[0] == topGroupRow.key[0]);
106+
grid.repaintRows(affectedGroupRows.map((g) => g.rowIndex));
107+
}
108+
}
109+
110+
areKeysSelected(keysToCheck: any[], selectedKeys: any[]): boolean | undefined {
111+
if (selectedKeys.length == 0) { return false; }
112+
const intersectionCount = keysToCheck.filter((k) => selectedKeys.includes(k)).length;
113+
if (intersectionCount === 0) { return false; }
114+
if (intersectionCount === keysToCheck.length) { return true; }
115+
return undefined;
116+
}
117+
118+
getChildRowKeys(grid: dxDataGrid, groupRowKey: string[]): any[] {
119+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
120+
return this.groupChildKeys[this.calcCheckBoxId(grid, groupRowKey) as any];
121+
}
122+
123+
calcCheckBoxId(grid: dxDataGrid, groupRowKey: string[]): string {
124+
const gridId: string = grid.element().id;
125+
return `${gridId}groupCheckBox${groupRowKey.join('')}`;
126+
}
127+
128+
collectGroupedColumns(grid: dxDataGrid): DxDataGridTypes.Column[] {
129+
const allColumns: DxDataGridTypes.Column[] = grid.getVisibleColumns();
130+
return allColumns.filter((c: DxDataGridTypes.Column) => c.groupIndex != undefined && c.groupIndex >= 0)
131+
.sort((a, b) => {
132+
if (!a.groupIndex || !b.groupIndex) return 0;
133+
return a.groupIndex > b.groupIndex ? 1 : -1;
134+
});
135+
}
136+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Pipe, PipeTransform } from '@angular/core';
2+
import { DxDataGridTypes } from 'devextreme-angular/ui/data-grid';
3+
4+
@Pipe({
5+
name: 'groupText',
6+
})
7+
export class GroupTextPipe implements PipeTransform {
8+
transform(value: DxDataGridTypes.ColumnGroupCellTemplateData): string {
9+
let text = `${value.column.caption}: ${value.displayValue}`;
10+
if (value.groupContinuedMessage) text += ` (${value.groupContinuedMessage})`;
11+
if (value.groupContinuesMessage) text += ` (${value.groupContinuesMessage})`;
12+
return text;
13+
}
14+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<div class="default-style">
2+
<dx-data-grid
3+
[dataSource]="dataSource"
4+
[remoteOperations]="true"
5+
[width]="'100%'"
6+
[height]="604"
7+
[showBorders]="true"
8+
[selectedRowKeys]="selectedRowKeys"
9+
>
10+
<div *dxTemplate="let group of 'groupCellTemplate'">
11+
<group-row-selectable
12+
[groupCellData]="group"
13+
[childRowKeys]="helper?.getChildRowKeys(group.component, group.key)"
14+
(onInitialized)="groupRowInit($event)"
15+
>
16+
</group-row-selectable>
17+
</div>
18+
<dxo-selection
19+
[deferred]="false"
20+
mode="multiple"
21+
[allowSelectAll]="true"
22+
showCheckBoxesMode="always"
23+
></dxo-selection>
24+
<dxo-paging [pageSize]="12"></dxo-paging>
25+
<dxo-group-panel [visible]="true"></dxo-group-panel>
26+
<dxo-grouping [autoExpandAll]="false"></dxo-grouping>
27+
<dxi-column dataField="CustomerID" caption="Customer">
28+
<dxo-lookup
29+
[dataSource]="customersData"
30+
valueExpr="Value"
31+
displayExpr="Text"
32+
></dxo-lookup>
33+
</dxi-column>
34+
<dxi-column dataField="OrderDate" dataType="date"> </dxi-column>
35+
<dxi-column dataField="Freight"> </dxi-column>
36+
<dxi-column dataField="ShipCountry" [groupIndex]="0"> </dxi-column>
37+
<dxi-column dataField="ShipCity" [groupIndex]="2"> </dxi-column>
38+
<dxi-column
39+
dataField="ShipVia"
40+
caption="Shipping Company"
41+
dataType="number"
42+
[groupIndex]="1"
43+
>
44+
<dxo-lookup
45+
[dataSource]="shippersData"
46+
valueExpr="Value"
47+
displayExpr="Text"
48+
></dxo-lookup>
49+
</dxi-column>
50+
</dx-data-grid>
51+
</div>

0 commit comments

Comments
 (0)