Skip to content

Commit aa9104f

Browse files
authored
CardView: fix sotring extra data source loadings (Satsxnln) (DevExpress#29940)
1 parent ee334c9 commit aa9104f

File tree

6 files changed

+227
-18
lines changed

6 files changed

+227
-18
lines changed

packages/devextreme/js/__internal/grids/new/card_view/header_panel/view.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ColumnChooserController, ColumnChooserView } from '../../grid_core/colu
88
import type { Column } from '../../grid_core/columns_controller/types';
99
import { FilterController } from '../../grid_core/filtering/filter_controller';
1010
import { HeaderFilterViewController } from '../../grid_core/filtering/header_filter/view_controller';
11-
import { SortingController } from '../../grid_core/sorting_controller/sorting_controller';
11+
import { SortingController } from '../../grid_core/sorting_controller/index';
1212
import { ContextMenuController } from '../context_menu/index';
1313
import { OptionsController } from '../options_controller';
1414
import type { Props as ColumnSortableProps } from './column_sortable';

packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { createPromise } from '@ts/core/utils/promise';
1111
import { ColumnsController } from '../columns_controller/columns_controller';
1212
import { FilterController } from '../filtering/filter_controller';
1313
import { OptionsController } from '../options_controller/options_controller';
14-
import { SortingController } from '../sorting_controller/sorting_controller';
14+
import { SortingController } from '../sorting_controller/index';
1515
import { StoreLoadAdapter } from './store_load_adapter/index';
1616
import type { DataObject, Key } from './types';
1717
import {
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/* eslint-disable spellcheck/spell-checker */
2+
import {
3+
beforeEach, describe, expect, it, jest,
4+
} from '@jest/globals';
5+
import { CustomStore } from '@js/common/data';
6+
import CardView from '@ts/grids/new/card_view/widget';
7+
import type { Options as GridCoreOptions } from '@ts/grids/new/grid_core/options';
8+
import { rerender } from 'inferno';
9+
10+
const setup = (options: GridCoreOptions = {}): CardView => {
11+
const container = document.createElement('div');
12+
const { body } = document;
13+
body.append(container);
14+
15+
const cardView = new CardView(container, options);
16+
17+
rerender();
18+
19+
return cardView;
20+
};
21+
22+
describe('SortingController', () => {
23+
describe('Integration tests', () => {
24+
let storeLoadMock: Function = jest.fn();
25+
26+
beforeEach(() => {
27+
storeLoadMock = jest
28+
.fn()
29+
.mockImplementation(() => [
30+
{ id: 0, A: 'A_0', B: 'B_0' },
31+
{ id: 1, A: 'A_1', B: 'B_1' },
32+
]);
33+
});
34+
35+
describe('Single mode', () => {
36+
it('Should not trigger additional load on initial sorting', () => {
37+
const cardView = setup({
38+
dataSource: new CustomStore({
39+
load: storeLoadMock as any,
40+
totalCount: (() => 2) as any,
41+
}),
42+
keyExpr: 'id',
43+
columns: ['A', 'B'],
44+
sorting: {
45+
mode: 'single',
46+
},
47+
});
48+
49+
const [firstCol] = cardView.getVisibleColumns();
50+
// @ts-expect-error access private property
51+
cardView.sortingController.onSingleModeSortClick(firstCol, new MouseEvent('click'));
52+
53+
// NOTE: 1 -> initial load + 1 -> load on sorting
54+
expect(storeLoadMock).toHaveBeenCalledTimes(2);
55+
});
56+
57+
it('Should not trigger additional load on sorting clear', () => {
58+
const cardView = setup({
59+
dataSource: new CustomStore({
60+
load: storeLoadMock as any,
61+
totalCount: (() => 2) as any,
62+
}),
63+
keyExpr: 'id',
64+
columns: [
65+
{ dataField: 'A', sortOrder: 'asc' },
66+
'B',
67+
],
68+
sorting: {
69+
mode: 'single',
70+
},
71+
});
72+
73+
const [firstCol] = cardView.getVisibleColumns();
74+
// @ts-expect-error access private property
75+
cardView.sortingController.onSingleModeSortClick(firstCol, new MouseEvent('click', { ctrlKey: true }));
76+
77+
// NOTE: 1 -> initial load + 1 -> sort clear
78+
expect(storeLoadMock).toHaveBeenCalledTimes(2);
79+
});
80+
81+
it('Should not trigger additional load on sorting column change', () => {
82+
const cardView = setup({
83+
dataSource: new CustomStore({
84+
load: storeLoadMock as any,
85+
totalCount: (() => 2) as any,
86+
}),
87+
keyExpr: 'id',
88+
columns: [
89+
'A',
90+
{ dataField: 'B', sortOrder: 'asc' },
91+
],
92+
sorting: {
93+
mode: 'multiple',
94+
},
95+
});
96+
97+
const [firstCol] = cardView.getVisibleColumns();
98+
// @ts-expect-error access private property
99+
cardView.sortingController.onSingleModeSortClick(firstCol, new MouseEvent('click'));
100+
101+
// NOTE: 1 -> initial load + 1 -> load on sorting
102+
expect(storeLoadMock).toHaveBeenCalledTimes(2);
103+
});
104+
});
105+
106+
describe('Multiple mode', () => {
107+
it('Should not trigger additional load on initial sorting', () => {
108+
const cardView = setup({
109+
dataSource: new CustomStore({
110+
load: storeLoadMock as any,
111+
totalCount: (() => 2) as any,
112+
}),
113+
keyExpr: 'id',
114+
columns: ['A', 'B'],
115+
sorting: {
116+
mode: 'multiple',
117+
},
118+
});
119+
120+
const [firstCol] = cardView.getVisibleColumns();
121+
// @ts-expect-error access private property
122+
cardView.sortingController.onMultipleModeSortClick(firstCol, new MouseEvent('click'));
123+
124+
// NOTE: 1 -> initial load + 1 -> load on sorting
125+
expect(storeLoadMock).toHaveBeenCalledTimes(2);
126+
});
127+
128+
it('Should not trigger additional load on sorting clear', () => {
129+
const cardView = setup({
130+
dataSource: new CustomStore({
131+
load: storeLoadMock as any,
132+
totalCount: (() => 2) as any,
133+
}),
134+
keyExpr: 'id',
135+
columns: [
136+
{ dataField: 'A', sortOrder: 'asc', sortIndex: 0 },
137+
{ dataField: 'B', sortOrder: 'asc', sortIndex: 1 },
138+
],
139+
sorting: {
140+
mode: 'single',
141+
},
142+
});
143+
144+
const [firstCol] = cardView.getVisibleColumns();
145+
// @ts-expect-error access private property
146+
cardView.sortingController.onSingleModeSortClick(firstCol, new MouseEvent('click', { ctrlKey: true }));
147+
148+
// NOTE: 1 -> initial load + 1 -> sort clear
149+
expect(storeLoadMock).toHaveBeenCalledTimes(2);
150+
});
151+
152+
it('Should not trigger additional load on adding sorting column', () => {
153+
const cardView = setup({
154+
dataSource: new CustomStore({
155+
load: storeLoadMock as any,
156+
totalCount: (() => 2) as any,
157+
}),
158+
keyExpr: 'id',
159+
columns: [
160+
'A',
161+
{ dataField: 'B', sortOrder: 'asc', sortIndex: 0 },
162+
],
163+
sorting: {
164+
mode: 'single',
165+
},
166+
});
167+
168+
const [firstCol] = cardView.getVisibleColumns();
169+
// @ts-expect-error access private property
170+
cardView.sortingController.onSingleModeSortClick(firstCol, new MouseEvent('click', { shiftKey: true }));
171+
172+
// NOTE: 1 -> initial load + 1 -> load on sorting
173+
expect(storeLoadMock).toHaveBeenCalledTimes(2);
174+
});
175+
176+
it('Should not trigger additional load on sorting column change', () => {
177+
const cardView = setup({
178+
dataSource: new CustomStore({
179+
load: storeLoadMock as any,
180+
totalCount: (() => 2) as any,
181+
}),
182+
keyExpr: 'id',
183+
columns: [
184+
'A',
185+
{ dataField: 'B', sortOrder: 'asc', sortIndex: 0 },
186+
],
187+
sorting: {
188+
mode: 'single',
189+
},
190+
});
191+
192+
const [firstCol] = cardView.getVisibleColumns();
193+
// @ts-expect-error access private property
194+
cardView.sortingController.onSingleModeSortClick(firstCol, new MouseEvent('click'));
195+
196+
// NOTE: 1 -> initial load + 1 -> load on sorting
197+
expect(storeLoadMock).toHaveBeenCalledTimes(2);
198+
});
199+
});
200+
});
201+
});

packages/devextreme/js/__internal/grids/new/grid_core/sorting_controller/sorting_controller.ts renamed to packages/devextreme/js/__internal/grids/new/grid_core/sorting_controller/controller.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ReadonlySignal } from '@preact/signals-core';
2-
import { computed } from '@preact/signals-core';
2+
import { batch, computed } from '@preact/signals-core';
33

44
import { ColumnsController } from '../columns_controller/index';
55
import type { Column } from '../columns_controller/types';
@@ -121,22 +121,26 @@ export class SortingController {
121121
if (!column.allowSorting) {
122122
return;
123123
}
124-
const isCtrl = e.ctrlKey || e.metaKey;
125124

125+
const isCtrl = e.ctrlKey || e.metaKey;
126126
const isClearSorting = !!column.sortOrder && isCtrl;
127+
127128
if (isClearSorting) {
128129
this.clearSorting();
129130
return;
130131
}
131132

132133
const isClearSortingRequired = (!column.sortOrder && !isCtrl)
133-
|| this.sortedColumns.peek().length > 1;
134-
if (isClearSortingRequired) {
135-
this.clearSorting();
136-
}
137-
134+
|| this.sortedColumns.peek().length > 1;
138135
const nextSortOrder = getNextSortOrder(column.sortOrder, isCtrl);
139-
this.columnsController.columnOption(column, 'sortOrder', nextSortOrder);
136+
137+
batch(() => {
138+
if (isClearSortingRequired) {
139+
this.clearSorting();
140+
}
141+
142+
this.columnsController.columnOption(column, 'sortOrder', nextSortOrder);
143+
});
140144
}
141145

142146
public onMultipleModeSortClick(column: Column, e: KeyboardEvent | MouseEvent): void {
@@ -146,19 +150,23 @@ export class SortingController {
146150

147151
const isCtrl = e.ctrlKey || e.metaKey;
148152
const hasNothingToChange = !column.sortOrder && isCtrl && !e.shiftKey;
153+
149154
if (hasNothingToChange) {
150155
return;
151156
}
152157

153158
const nextSortOrder = getNextSortOrder(column.sortOrder, isCtrl);
154159
const isClearSortingRequired = !isCtrl && !e.shiftKey;
155-
if (isClearSortingRequired) {
156-
this.clearSorting();
157-
}
158160

159-
// TODO: Resolve the nested update issue
160-
// this.columnsController.columnOption(column, 'sortOrder', nextSortOrder);
161-
this.updateColumnSortOrder(column, nextSortOrder);
161+
batch(() => {
162+
if (isClearSortingRequired) {
163+
this.clearSorting();
164+
}
165+
166+
// TODO: Resolve the nested update issue
167+
// this.columnsController.columnOption(column, 'sortOrder', nextSortOrder);
168+
this.updateColumnSortOrder(column, nextSortOrder);
169+
});
162170
}
163171

164172
private updateColumnSortOrder(column, nextSortOrder): void {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1+
export { SortingController } from './controller';
12
export { defaultOptions, type Options } from './options';
23
export { PublicMethods } from './public_methods';
3-
export { SortingController } from './sorting_controller';

packages/devextreme/js/__internal/grids/new/grid_core/widget.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ import { defaultOptions, defaultOptionsRules, type Options } from './options';
3030
import { PagerView } from './pager/view';
3131
import * as SearchControllerModule from './search/index';
3232
import * as SelectionControllerModule from './selection/index';
33+
import type { SortingController } from './sorting_controller/index';
3334
import * as SortingControllerModule from './sorting_controller/index';
34-
import type { SortingController } from './sorting_controller/sorting_controller';
3535
import { ToolbarController } from './toolbar/controller';
3636
import { ToolbarView } from './toolbar/view';
3737
import { WidgetMock } from './widget_mock';

0 commit comments

Comments
 (0)