Skip to content

Commit 73c288b

Browse files
committed
feat(backend): add option to use local filtering/sorting strategy
- add 2x new flags (useLocalFiltering & useLocalSorting) that could optionally be used with a backend service
1 parent dc50117 commit 73c288b

File tree

4 files changed

+91
-18
lines changed

4 files changed

+91
-18
lines changed

src/app/examples/grid-odata.component.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,9 @@ export class GridOdataComponent implements OnInit {
110110
backendServiceApi: {
111111
service: new GridOdataService(),
112112
options: {
113-
// useLocalFiltering: true,
114113
enableCount: this.isCountEnabled, // add the count in the OData query, which will return a property named "odata.count" (v2) or "@odata.count" (v4)
115114
version: this.odataVersion // defaults to 2, the query string is slightly different between OData 2 and 4
116-
} as OdataOption,
115+
},
117116
preProcess: () => this.displaySpinner(true),
118117
process: (query) => this.getCustomerApiCall(query),
119118
postProcess: (response) => {

src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid-constructor.spec.ts

+55-12
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
SharedService,
2121
SortService,
2222
} from '../../services';
23-
import { Column, CurrentFilter, CurrentSorter, GridOption, GridState, GridStateChange, GridStateType, Pagination } from '../../models';
23+
import { Column, CurrentFilter, CurrentSorter, GridOption, GridState, GridStateChange, GridStateType, Pagination, GraphqlServiceApi, GraphqlServiceOption } from '../../models';
2424
import { Filters } from '../../filters';
2525
import { Editors } from '../../editors';
2626
import * as utilities from '../../services/backend-utilities';
@@ -490,6 +490,24 @@ describe('Angular-Slickgrid Custom Component instantiated via Constructor', () =
490490

491491
expect(syncSpy).toHaveBeenCalledWith(component.grid, true, false);
492492
});
493+
494+
it('should bind local filter when "enableFiltering" is set', () => {
495+
const bindLocalSpy = jest.spyOn(filterServiceStub, 'bindLocalOnFilter');
496+
497+
component.gridOptions = { enableFiltering: true } as GridOption;
498+
component.ngAfterViewInit();
499+
500+
expect(bindLocalSpy).toHaveBeenCalledWith(mockGrid, mockDataView);
501+
});
502+
503+
it('should bind local sort when "enableSorting" is set', () => {
504+
const bindLocalSpy = jest.spyOn(sortServiceStub, 'bindLocalOnSort');
505+
506+
component.gridOptions = { enableSorting: true } as GridOption;
507+
component.ngAfterViewInit();
508+
509+
expect(bindLocalSpy).toHaveBeenCalledWith(mockGrid, mockDataView);
510+
});
493511
});
494512

495513
describe('flag checks', () => {
@@ -820,7 +838,7 @@ describe('Angular-Slickgrid Custom Component instantiated via Constructor', () =
820838

821839
it('should execute backend service "init" method when set', () => {
822840
const mockPagination = { pageNumber: 1, pageSizes: [10, 25, 50], pageSize: 10, totalItems: 100 };
823-
const mockGraphqlOptions = { extraQueryArguments: [{ field: 'userId', value: 123 }] };
841+
const mockGraphqlOptions = { datasetName: 'users', extraQueryArguments: [{ field: 'userId', value: 123 }] } as GraphqlServiceOption;
824842
const bindBackendSpy = jest.spyOn(sortServiceStub, 'bindBackendOnSort');
825843
const mockGraphqlService2 = { ...mockGraphqlService, init: jest.fn() } as unknown as GraphqlService;
826844
const initSpy = jest.spyOn(mockGraphqlService2, 'init');
@@ -831,8 +849,8 @@ describe('Angular-Slickgrid Custom Component instantiated via Constructor', () =
831849
service: mockGraphqlService2,
832850
options: mockGraphqlOptions,
833851
preProcess: () => jest.fn(),
834-
process: (query) => new Promise((resolve) => resolve('process resolved')),
835-
},
852+
process: (query) => new Promise((resolve) => resolve({ data: { users: { nodes: [], totalCount: 100 } } })),
853+
} as GraphqlServiceApi,
836854
pagination: mockPagination,
837855
} as GridOption;
838856
component.ngAfterViewInit();
@@ -841,32 +859,40 @@ describe('Angular-Slickgrid Custom Component instantiated via Constructor', () =
841859
expect(initSpy).toHaveBeenCalledWith(mockGraphqlOptions, mockPagination, mockGrid);
842860
});
843861

844-
it('should bind local sort when "enableSorting" is set', () => {
845-
const bindLocalSpy = jest.spyOn(sortServiceStub, 'bindLocalOnSort');
862+
it('should call bind backend sorting when "enableSorting" is set', () => {
863+
const bindBackendSpy = jest.spyOn(sortServiceStub, 'bindBackendOnSort');
846864

847-
component.gridOptions = { enableSorting: true } as GridOption;
865+
component.gridOptions = {
866+
enableSorting: true,
867+
backendServiceApi: {
868+
service: mockGraphqlService,
869+
preProcess: () => jest.fn(),
870+
process: (query) => new Promise((resolve) => resolve('process resolved')),
871+
}
872+
} as GridOption;
848873
component.ngAfterViewInit();
849874

850-
expect(bindLocalSpy).toHaveBeenCalledWith(mockGrid, mockDataView);
875+
expect(bindBackendSpy).toHaveBeenCalledWith(mockGrid, mockDataView);
851876
});
852877

853-
it('should reflect column filters when "enableSorting" is set', () => {
854-
const bindBackendSpy = jest.spyOn(sortServiceStub, 'bindBackendOnSort');
878+
it('should call bind local sorting when "enableSorting" is set and "useLocalSorting" is set as well', () => {
879+
const bindLocalSpy = jest.spyOn(sortServiceStub, 'bindLocalOnSort');
855880

856881
component.gridOptions = {
857882
enableSorting: true,
858883
backendServiceApi: {
859884
service: mockGraphqlService,
885+
useLocalSorting: true,
860886
preProcess: () => jest.fn(),
861887
process: (query) => new Promise((resolve) => resolve('process resolved')),
862888
}
863889
} as GridOption;
864890
component.ngAfterViewInit();
865891

866-
expect(bindBackendSpy).toHaveBeenCalledWith(mockGrid, mockDataView);
892+
expect(bindLocalSpy).toHaveBeenCalledWith(mockGrid, mockDataView);
867893
});
868894

869-
it('should reflect column filters when "enableFiltering" is set', () => {
895+
it('should call bind backend filtering when "enableFiltering" is set', () => {
870896
const initSpy = jest.spyOn(filterServiceStub, 'init');
871897
const bindLocalSpy = jest.spyOn(filterServiceStub, 'bindLocalOnFilter');
872898
const populateSpy = jest.spyOn(filterServiceStub, 'populateColumnFilterSearchTermPresets');
@@ -879,6 +905,23 @@ describe('Angular-Slickgrid Custom Component instantiated via Constructor', () =
879905
expect(populateSpy).not.toHaveBeenCalled();
880906
});
881907

908+
it('should call bind local filtering when "enableFiltering" is set and "useLocalFiltering" is set as well', () => {
909+
const bindLocalSpy = jest.spyOn(filterServiceStub, 'bindLocalOnFilter');
910+
911+
component.gridOptions = {
912+
enableFiltering: true,
913+
backendServiceApi: {
914+
service: mockGraphqlService,
915+
useLocalFiltering: true,
916+
preProcess: () => jest.fn(),
917+
process: (query) => new Promise((resolve) => resolve('process resolved')),
918+
}
919+
} as GridOption;
920+
component.ngAfterViewInit();
921+
922+
expect(bindLocalSpy).toHaveBeenCalledWith(mockGrid, mockDataView);
923+
});
924+
882925
it('should reflect column filters when "enableFiltering" is set', () => {
883926
const initSpy = jest.spyOn(filterServiceStub, 'init');
884927
const bindBackendSpy = jest.spyOn(filterServiceStub, 'bindBackendOnFilter');

src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,12 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
418418

419419
// bind external sorting (backend) when available or default onSort (dataView)
420420
if (gridOptions.enableSorting && !this.customDataView) {
421-
gridOptions.backendServiceApi ? this.sortService.bindBackendOnSort(grid, dataView) : this.sortService.bindLocalOnSort(grid, dataView);
421+
// bind external sorting (backend) unless specified to use the local one
422+
if (gridOptions.backendServiceApi && !gridOptions.backendServiceApi.useLocalSorting) {
423+
this.sortService.bindBackendOnSort(grid, dataView);
424+
} else {
425+
this.sortService.bindLocalOnSort(grid, dataView);
426+
}
422427
}
423428

424429
// bind external filter (backend) when available or default onFilter (dataView)
@@ -429,7 +434,12 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
429434
if (gridOptions.presets && Array.isArray(gridOptions.presets.filters) && gridOptions.presets.filters.length > 0) {
430435
this.filterService.populateColumnFilterSearchTermPresets(gridOptions.presets.filters);
431436
}
432-
gridOptions.backendServiceApi ? this.filterService.bindBackendOnFilter(grid, this.dataView) : this.filterService.bindLocalOnFilter(grid, this.dataView);
437+
// bind external filter (backend) unless specified to use the local one
438+
if (gridOptions.backendServiceApi && !gridOptions.backendServiceApi.useLocalFiltering) {
439+
this.filterService.bindBackendOnFilter(grid, this.dataView);
440+
} else {
441+
this.filterService.bindLocalOnFilter(grid, this.dataView);
442+
}
433443
}
434444

435445
// if user set an onInit Backend, we'll run it right away (and if so, we also need to run preProcess, internalPostProcess & postProcess)

src/app/modules/angular-slickgrid/models/backendServiceApi.interface.ts

+23-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,35 @@ import { Observable } from 'rxjs';
33
import { BackendService } from './backendService.interface';
44

55
export interface BackendServiceApi {
6+
/** How long to wait until we start querying backend to avoid sending too many requests to backend server. Default to 750ms */
7+
filterTypingDebounce?: number;
8+
69
/** Backend Service Options */
710
options?: any;
811

912
/** Backend Service instance (could be OData, GraphQL or any other Backend Service) */
1013
service: BackendService;
1114

15+
/**
16+
* Do we want to optionally use the local (in memory) filtering strategy?
17+
* This could be useful if user wishes to load the entire dataset only once with a OData/GraphQL Backend Service
18+
* and then use local filter strategy (with SlickGrid DataView) with only current local dataset (only what got loaded in memory).
19+
* This option could be used alone and/or with the "useLocalSorting" property.
20+
*/
21+
useLocalFiltering?: boolean;
22+
23+
/**
24+
* Do we want to optionally use the local (in memory) sorting strategy?
25+
* This could be useful if user wishes to load the entire dataset only once with a OData/GraphQL Backend Service
26+
* and then use local sorting strategy (with SlickGrid DataView) with only current local dataset (only what got loaded in memory).
27+
* This option could be used alone and/or with the "useLocalFiltering" property.
28+
*/
29+
useLocalSorting?: boolean;
30+
31+
// --
32+
// available methods
33+
// ------------------
34+
1235
/** On error callback, when an error is thrown by the process execution */
1336
onError?: (e) => void;
1437

@@ -24,8 +47,6 @@ export interface BackendServiceApi {
2447
/** After executing the query, what action to perform? For example, stop the spinner */
2548
postProcess?: (response: any) => void;
2649

27-
/** How long to wait until we start querying backend to avoid sending too many requests to backend server. Default to 750ms */
28-
filterTypingDebounce?: number;
2950

3051
/**
3152
* INTERNAL USAGE ONLY by Angular-Slickgrid

0 commit comments

Comments
 (0)