Skip to content

Commit d8dc6de

Browse files
authored
CardView: dataController -> paging in the remote OData DataSource not working (DevExpress#29877)
1 parent 5a7fd83 commit d8dc6de

File tree

4 files changed

+134
-18
lines changed

4 files changed

+134
-18
lines changed

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

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@ import type { Options } from '../options';
55
import { OptionsControllerMock } from '../options_controller/options_controller.mock';
66
import { DataController } from './data_controller';
77

8-
const getControllers = (options?: Options) => {
8+
const setup = (options?: Options) => {
99
const context = getContext(options ?? {});
1010

11-
const optionsController = context.get(OptionsControllerMock);
12-
1311
return {
14-
optionsController,
12+
optionsController: context.get(OptionsControllerMock),
1513
dataController: context.get(DataController),
1614
};
1715
};
@@ -21,7 +19,7 @@ const generateData = (length: number) => [...new Array(length)].map((_, index) =
2119
describe('DataController', () => {
2220
describe('pageIndex', () => {
2321
it('does not change after pageSize increased and pageIndex < pageCount', async () => {
24-
const { optionsController, dataController } = getControllers({
22+
const { optionsController, dataController } = setup({
2523
dataSource: generateData(20),
2624
paging: {
2725
pageIndex: 1,
@@ -37,7 +35,7 @@ describe('DataController', () => {
3735
});
3836

3937
it('set to last page after pageSize increased and pageIndex >= pageCount', async () => {
40-
const { optionsController, dataController } = getControllers({
38+
const { optionsController, dataController } = setup({
4139
dataSource: generateData(20),
4240
paging: {
4341
pageIndex: 3,
@@ -53,7 +51,7 @@ describe('DataController', () => {
5351
});
5452

5553
it('set to last and only page after pageSize increased and pageIndex >= pageCount == 1', async () => {
56-
const { optionsController, dataController } = getControllers({
54+
const { optionsController, dataController } = setup({
5755
dataSource: generateData(20),
5856
paging: {
5957
pageIndex: 1,
@@ -68,4 +66,46 @@ describe('DataController', () => {
6866
expect(optionsController.oneWay('paging.pageIndex').peek()).toEqual(0);
6967
});
7068
});
69+
70+
describe('regressions', () => {
71+
it('should work good with odata store', async () => {
72+
const { dataController } = setup({
73+
dataSource: {
74+
store: {
75+
type: 'odata',
76+
version: 2,
77+
url: 'https://js.devexpress.com/Demos/DevAV/odata/Products',
78+
key: 'Product_ID',
79+
},
80+
select: [
81+
'Product_ID',
82+
'Product_Name',
83+
'Product_Cost',
84+
'Product_Sale_Price',
85+
'Product_Retail_Price',
86+
'Product_Current_Inventory',
87+
],
88+
filter: ['Product_Current_Inventory', '>', 0],
89+
},
90+
keyExpr: 'Product_ID',
91+
columns: ['Product_ID', 'Product_Name'],
92+
paging: {
93+
pageSize: 3,
94+
},
95+
});
96+
97+
const getCurrentItemIds = () => dataController.items.value.map((item) => item.Product_ID);
98+
99+
await dataController.waitLoaded();
100+
101+
expect(dataController.pageIndex.value).toBe(0);
102+
expect(getCurrentItemIds()).toEqual([1, 2, 4]);
103+
104+
dataController.pageIndex.value = 1;
105+
await dataController.waitLoaded();
106+
107+
expect(dataController.pageIndex.value).toBe(1);
108+
expect(getCurrentItemIds()).toEqual([5, 6, 7]);
109+
});
110+
});
71111
});

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { DataSource } from '@js/common/data';
2+
import type { FilterDescriptor } from '@js/common/data.types';
23
import ArrayStore from '@js/common/data/array_store';
34
import { Deferred } from '@js/core/utils/deferred';
45
import { isDefined } from '@js/core/utils/type';
@@ -8,6 +9,7 @@ import { equalByValue } from '@ts/core/utils/m_common';
89
import type { PromiseWithResolvers } from '@ts/core/utils/promise';
910
import { createPromise } from '@ts/core/utils/promise';
1011

12+
import gridCoreUtils from '../../../grid_core/m_utils';
1113
import { ColumnsController } from '../columns_controller/columns_controller';
1214
import { FilterController } from '../filtering/filter_controller';
1315
import { OptionsController } from '../options_controller/options_controller';
@@ -43,6 +45,8 @@ export class DataController {
4345
),
4446
);
4547

48+
private previousDisplayFilter: FilterDescriptor = undefined;
49+
4650
// TODO
4751
private readonly cacheEnabled = this.options.oneWay('cacheEnabled');
4852

@@ -131,6 +135,10 @@ export class DataController {
131135
changedCallback();
132136
};
133137
const customizeStoreLoadOptionsCallback = (e): void => {
138+
e.storeLoadOptions.filter = this.combineFilterWithDisplayFilter(
139+
e.storeLoadOptions.filter,
140+
);
141+
134142
const localOptions = this.normalizedLocalOperations.peek();
135143
this.pendingLocalOperations[e.operationId] = getLocalLoadOptions(
136144
e.storeLoadOptions,
@@ -211,6 +219,7 @@ export class DataController {
211219
() => {
212220
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
213221
this.normalizedRemoteOptions.value;
222+
214223
if (this.dataSource.peek().isLoaded()) {
215224
// eslint-disable-next-line @typescript-eslint/no-floating-promises
216225
this.dataSource.peek().load();
@@ -229,6 +238,7 @@ export class DataController {
229238
const sortParameters = this.sortingController.sortParameters.value;
230239

231240
let someParamChanged = false;
241+
232242
if (dataSource.pageIndex() !== pageIndex) {
233243
dataSource.pageIndex(pageIndex);
234244
someParamChanged ||= true;
@@ -250,17 +260,19 @@ export class DataController {
250260
someParamChanged ||= true;
251261
}
252262

253-
if (!equalByValue(
254-
dataSource.filter() ?? null,
263+
const filterChanged = !equalByValue(
264+
this.previousDisplayFilter,
255265
displayFilter,
256266
{
257267
maxDepth: FILTER_OBJ_COMPARE_DEPTH,
258268
strict: true,
259269
},
260-
)) {
261-
dataSource.filter(displayFilter ?? null);
270+
);
271+
if (filterChanged && isLoaded) {
272+
this.dataSource.peek().pageIndex(0);
262273
someParamChanged ||= true;
263274
}
275+
this.previousDisplayFilter = displayFilter;
264276

265277
if (!equalByValue(dataSource.paginate(), pagingEnabled)) {
266278
dataSource.paginate(pagingEnabled);
@@ -280,6 +292,19 @@ export class DataController {
280292
);
281293
}
282294

295+
public getCombinedFilter(): FilterDescriptor {
296+
return this.combineFilterWithDisplayFilter(
297+
this.dataSource.peek().filter(),
298+
);
299+
}
300+
301+
private combineFilterWithDisplayFilter(filter: FilterDescriptor): FilterDescriptor {
302+
return gridCoreUtils.combineFilters([
303+
filter,
304+
this.filterController.displayFilter.peek(),
305+
]);
306+
}
307+
283308
private onChanged(dataSource: DataSource, e): void {
284309
let items = dataSource.items() as DataObject[];
285310

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

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
describe, expect, it, jest,
33
} from '@jest/globals';
4+
import { DataSource } from '@ts/data/data_source/m_data_source';
45
import ArrayStore from '@ts/data/m_array_store';
56

67
import { getContext } from '../di.test_utils';
@@ -100,11 +101,6 @@ describe('PublicMethods', () => {
100101
});
101102
});
102103
});
103-
describe('getFilter', () => {
104-
// TODO: add test once some filter module (header filter, filter row etc) is implemented
105-
it.skip('should return filter applied to dataSource', () => {
106-
});
107-
});
108104

109105
describe('keyOf', () => {
110106
it('should return key of given data object', () => {
@@ -171,4 +167,59 @@ describe('PublicMethods', () => {
171167
expect(gridCore.totalCount()).toBe(4);
172168
});
173169
});
170+
171+
describe('getCombinedFilter', () => {
172+
const innerSetup = ({ dataSourceFilter, columnFilterValues }) => setup({
173+
dataSource: new DataSource({
174+
store: {
175+
type: 'array',
176+
data: [{ a: 1 }, { a: 2 }, { a: 3 }],
177+
},
178+
filter: dataSourceFilter,
179+
}),
180+
columns: [
181+
{ dataField: 'a', filterValues: columnFilterValues },
182+
],
183+
});
184+
185+
describe('when displayFilter and filter from dataSource are empty', () => {
186+
it('should return empty filter', () => {
187+
const { gridCore } = innerSetup({
188+
dataSourceFilter: undefined,
189+
columnFilterValues: undefined,
190+
});
191+
expect(gridCore.getCombinedFilter()).toBe(undefined);
192+
});
193+
});
194+
195+
describe('when displayFilter is set and filter from dataSource is empty', () => {
196+
it('should return displayFilter filter', () => {
197+
const { gridCore } = innerSetup({
198+
dataSourceFilter: undefined,
199+
columnFilterValues: [1, 2],
200+
});
201+
expect(gridCore.getCombinedFilter()).toBe(undefined);
202+
});
203+
});
204+
205+
describe('when displayFilter is empty and filter from dataSource is set', () => {
206+
it('should return filter from dataSource', () => {
207+
const { gridCore } = innerSetup({
208+
dataSourceFilter: ['a', '=', 123],
209+
columnFilterValues: undefined,
210+
});
211+
expect(gridCore.getCombinedFilter()).toEqual(['a', '=', 123]);
212+
});
213+
});
214+
215+
describe('when displayFilter and filter from dataSource are set', () => {
216+
it('should combine filters', () => {
217+
const { gridCore } = innerSetup({
218+
dataSourceFilter: ['a', '=', 123],
219+
columnFilterValues: [1, 2],
220+
});
221+
expect(gridCore.getCombinedFilter()).toEqual(['a', '=', 123]);
222+
});
223+
});
224+
});
174225
});

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ export function PublicMethods<T extends Constructor<GridCoreNewBase>>(GridCore:
3333
return store.byKey(key);
3434
}
3535

36-
public getFilter(): FilterDescriptor | FilterDescriptor[] {
37-
return this.getDataSource().filter();
36+
public getCombinedFilter(): FilterDescriptor | FilterDescriptor[] {
37+
return this.dataController.getCombinedFilter();
3838
}
3939

4040
public keyOf(obj: DataObject) {

0 commit comments

Comments
 (0)