Skip to content

Commit

Permalink
fix(filters): Grid State filters should always include an operator (#238
Browse files Browse the repository at this point in the history
)

* fix(filters): Grid State filters should always include an operator
  • Loading branch information
ghiscoding committed Jan 19, 2021
1 parent 563c0fa commit f64ed37
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 28 deletions.
14 changes: 10 additions & 4 deletions packages/common/src/interfaces/filter.interface.ts
Expand Up @@ -14,15 +14,21 @@ export interface Filter {
/** SlickGrid grid object */
grid: SlickGrid;

/** Array of defined search terms to pre-load */
searchTerms?: SearchTerm[];
/** The default search operator for the filter when not provided */
defaultOperator?: OperatorString | OperatorType;

/** The search operator for the filter */
operator: OperatorType | OperatorString;

/** You can use "params" to pass any types of arguments to your Filter */
/** You can use "params" to pass any generic arguments to your Filter */
params?: any | any[];

/** Array of defined search terms to pre-load */
searchTerms?: SearchTerm[];

// --
// public functions

/** Filter class initialization, executed by the FilterService right after creating the Filter */
init: (args: FilterArguments, isFilterFirstRender?: boolean) => void;

Expand All @@ -36,5 +42,5 @@ export interface Filter {
getValues?: () => SearchTerm | SearchTerm[] | undefined;

/** Set value(s) on the DOM element */
setValues: (values: SearchTerm | SearchTerm[] | undefined) => void;
setValues: (values: SearchTerm | SearchTerm[] | undefined, operator?: OperatorType | OperatorString) => void;
}
15 changes: 8 additions & 7 deletions packages/common/src/services/__tests__/filter.service.spec.ts
Expand Up @@ -8,6 +8,7 @@ import {
BackendService,
BackendServiceApi,
Column,
ColumnFilters,
CurrentFilter,
GridMenuItem,
GridOption,
Expand Down Expand Up @@ -1337,11 +1338,11 @@ describe('FilterService', () => {
gridStub.onHeaderRowCellRendered.notify(mockArgs1 as any, new Slick.EventData(), gridStub);
gridStub.onHeaderRowCellRendered.notify(mockArgs2 as any, new Slick.EventData(), gridStub);

const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', searchTerms: ['map'] } };
const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', operator: 'Contains', searchTerms: ['map'] } };
service.updateFilters([{ columnId: 'file', operator: '', searchTerms: ['map'] }], true, true, true);
const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters });

expect(pubSubSpy).toHaveBeenCalledWith(`onFilterChanged`, [{ columnId: 'file', searchTerms: ['map',] }]);
expect(pubSubSpy).toHaveBeenCalledWith(`onFilterChanged`, [{ columnId: 'file', operator: 'Contains', searchTerms: ['map',] }]);
expect(output).toBe(true);
expect(preFilterSpy).toHaveBeenCalledWith(dataset, columnFilters);
expect(preFilterSpy).toHaveReturnedWith([21, 4, 5]);
Expand All @@ -1361,11 +1362,11 @@ describe('FilterService', () => {
gridStub.onHeaderRowCellRendered.notify(mockArgs1 as any, new Slick.EventData(), gridStub);
gridStub.onHeaderRowCellRendered.notify(mockArgs2 as any, new Slick.EventData(), gridStub);

const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', searchTerms: ['map'] } };
const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', operator: 'Contains', searchTerms: ['map'] } };
service.updateFilters([{ columnId: 'file', operator: '', searchTerms: ['map'] }], true, true, true);
const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters });

expect(pubSubSpy).toHaveBeenCalledWith(`onFilterChanged`, [{ columnId: 'file', searchTerms: ['map',] }]);
expect(pubSubSpy).toHaveBeenCalledWith(`onFilterChanged`, [{ columnId: 'file', operator: 'Contains', searchTerms: ['map'] }]);
expect(output).toBe(false);
expect(preFilterSpy).toHaveBeenCalledWith(dataset, columnFilters);
expect(preFilterSpy).toHaveReturnedWith([21, 4, 5]);
Expand All @@ -1385,13 +1386,13 @@ describe('FilterService', () => {
gridStub.onHeaderRowCellRendered.notify(mockArgs1 as any, new Slick.EventData(), gridStub);
gridStub.onHeaderRowCellRendered.notify(mockArgs2 as any, new Slick.EventData(), gridStub);

const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', searchTerms: ['unknown'] } };
const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', searchTerms: ['unknown'] } } as ColumnFilters;
service.updateFilters([{ columnId: 'file', operator: '', searchTerms: ['unknown'] }], true, true, true);
const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters });

expect(pubSubSpy).toHaveBeenCalledWith(`onFilterChanged`, [{ columnId: 'file', searchTerms: ['unknown',] }]);
expect(pubSubSpy).toHaveBeenCalledWith(`onFilterChanged`, [{ columnId: 'file', operator: 'Contains', searchTerms: ['unknown'] }]);
expect(output).toBe(false);
expect(preFilterSpy).toHaveBeenCalledWith(dataset, columnFilters);
expect(preFilterSpy).toHaveBeenCalledWith(dataset, { ...columnFilters, file: { ...columnFilters.file, operator: 'Contains' } }); // it will use Contains by default
expect(preFilterSpy).toHaveReturnedWith([]);
});
});
Expand Down
31 changes: 15 additions & 16 deletions packages/common/src/services/filter.service.ts
Expand Up @@ -31,7 +31,7 @@ import {
SlickNamespace,
} from './../interfaces/index';
import { executeBackendCallback, refreshBackendDataset } from './backend-utilities';
import { debounce, getDescendantProperty } from './utilities';
import { debounce, getDescendantProperty, mapOperatorByFieldType } from './utilities';
import { PubSubService } from '../services/pubSub.service';
import { SharedService } from './shared.service';

Expand All @@ -56,7 +56,7 @@ export class FilterService {
protected _eventHandler: SlickEventHandler;
protected _isFilterFirstRender = true;
protected _firstColumnIdRendered: string | number = '';
protected _filtersMetadata: any[] = [];
protected _filtersMetadata: Array<Filter> = [];
protected _columnFilters: ColumnFilters = {};
protected _grid: SlickGrid;
protected _onSearchChange: SlickEvent<OnSearchChangeEvent> | null;
Expand Down Expand Up @@ -126,9 +126,9 @@ export class FilterService {

// also destroy each Filter instances
if (Array.isArray(this._filtersMetadata)) {
this._filtersMetadata.forEach((filter: any) => {
if (filter && filter.destroy) {
filter.destroy(true);
this._filtersMetadata.forEach(filter => {
if (filter?.destroy) {
filter.destroy();
}
});
}
Expand Down Expand Up @@ -228,8 +228,8 @@ export class FilterService {
}

// find the filter object and call its clear method with true (the argument tells the method it was called by a clear filter)
const colFilter: Filter = this._filtersMetadata.find((filter: Filter) => filter.columnDef.id === columnId);
if (colFilter && colFilter.clear) {
const colFilter: Filter | undefined = this._filtersMetadata.find((filter: Filter) => filter.columnDef.id === columnId);
if (colFilter?.clear) {
colFilter.clear(true);
}

Expand All @@ -251,7 +251,7 @@ export class FilterService {
/** Clear the search filters (below the column titles) */
clearFilters(triggerChange = true) {
this._filtersMetadata.forEach((filter: Filter) => {
if (filter && filter.clear) {
if (filter?.clear) {
// clear element but don't trigger individual clear change,
// we'll do 1 trigger for all filters at once afterward
filter.clear(false);
Expand Down Expand Up @@ -362,7 +362,7 @@ export class FilterService {
if (typeof columnDef.queryFieldNameGetterFn === 'function') {
queryFieldName = columnDef.queryFieldNameGetterFn(item);
}
const fieldType = columnDef.filter?.type || columnDef.type || FieldType.string;
const fieldType = columnDef.filter?.type ?? columnDef.type ?? FieldType.string;
const filterSearchType = (columnDef.filterSearchType) ? columnDef.filterSearchType : null;
let cellValue = item[queryFieldName];

Expand Down Expand Up @@ -763,13 +763,13 @@ export class FilterService {
/** Add all created filters (from their template) to the header row section area */
protected addFilterTemplateToHeaderRow(args: { column: Column; grid: SlickGrid; node: HTMLElement }, isFilterFirstRender = true) {
const columnDef = args.column;
const columnId = columnDef && columnDef.id || '';
const columnId = columnDef?.id ?? '';

if (columnDef && columnId !== 'selector' && columnDef.filterable) {
let searchTerms: SearchTerm[] | undefined;
let operator: OperatorString | OperatorType | undefined;
const newFilter: Filter | undefined = this.filterFactory.createFilter(columnDef.filter);
operator = (columnDef && columnDef.filter && columnDef.filter.operator) || (newFilter && newFilter.operator);
operator = columnDef?.filter?.operator ?? newFilter?.operator;

if (this._columnFilters[columnDef.id]) {
searchTerms = this._columnFilters[columnDef.id].searchTerms || undefined;
Expand Down Expand Up @@ -818,7 +818,8 @@ export class FilterService {
const searchTerm = ((event && event.target) ? (event.target as HTMLInputElement).value : undefined);
const searchTerms = (args.searchTerms && Array.isArray(args.searchTerms)) ? args.searchTerms : (searchTerm ? [searchTerm] : undefined);
const columnDef = args.columnDef || null;
const columnId = columnDef && columnDef.id || '';
const columnId = columnDef?.id ?? '';
const fieldType = columnDef?.filter?.type ?? columnDef?.type ?? FieldType.string;
const operator = args.operator || undefined;
const hasSearchTerms = searchTerms && Array.isArray(searchTerms);
const termsCount = hasSearchTerms && searchTerms && searchTerms.length;
Expand All @@ -836,9 +837,7 @@ export class FilterService {
columnDef,
searchTerms,
};
if (operator) {
colFilter.operator = operator;
}
colFilter.operator = operator || mapOperatorByFieldType(fieldType);
this._columnFilters[colId] = colFilter;
}
}
Expand All @@ -857,7 +856,7 @@ export class FilterService {
columnId,
columnDef,
columnFilters: this._columnFilters,
operator,
operator: operator || mapOperatorByFieldType(fieldType),
searchTerms,
grid: this._grid
}, eventData);
Expand Down
2 changes: 1 addition & 1 deletion test/cypress/integration/example09.spec.js
Expand Up @@ -563,7 +563,7 @@ describe('Example 09 - OData Grid', () => {

cy.window().then((win) => {
// expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('Client sample, Grid State changed:: ', { newValues: [{ columnId: 'name', searchTerms: ['x'] }], type: 'filter' });
expect(win.console.log).to.be.calledWith('Client sample, Grid State changed:: ', { newValues: [{ columnId: 'name', operator: 'Contains', searchTerms: ['x'] }], type: 'filter' });
// expect(win.console.log).to.be.calledWith('Client sample, Grid State changed:: ', { newValues: { pageNumber: 1, pageSize: 10 }, type: 'pagination' });
});
});
Expand Down

0 comments on commit f64ed37

Please sign in to comment.