Skip to content

Commit

Permalink
feat(common): add "targetSelector" to onFilterChanged & Grid State (#813
Browse files Browse the repository at this point in the history
)
  • Loading branch information
ghiscoding authored Nov 12, 2022
1 parent ca9adfa commit a25791a
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 56 deletions.
3 changes: 3 additions & 0 deletions packages/common/src/interfaces/columnFilter.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ export interface ColumnFilter {
*/
skipCompoundOperatorFilterWithNullInput?: boolean;

/** Target element selector from which the filter was triggered from. */
targetSelector?: string;

/** What is the Field Type that can be used by the Filter (as precedence over the "type" set the column definition) */
type?: typeof FieldType[keyof typeof FieldType];

Expand Down
3 changes: 3 additions & 0 deletions packages/common/src/interfaces/currentFilter.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ export interface CurrentFilter {

/** Filter search terms */
searchTerms?: SearchTerm[];

/** Target element selector from which the filter was triggered from. */
targetSelector?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ export interface FilterChangedArgs {
operator: OperatorType | OperatorString;
searchTerms: SearchTerm[];
shouldTriggerQuery?: boolean;
targetSelector?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ export interface SearchColumnFilter {

/** What is the Field Type that can be used by the Filter (as precedence over the "type" set the column definition) */
type: typeof FieldType[keyof typeof FieldType];

/** Target element selector from which the filter was triggered from. */
targetSelector?: string;
}
32 changes: 32 additions & 0 deletions packages/common/src/services/__tests__/domUtilities.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
findFirstElementAttribute,
getElementOffsetRelativeToParent,
getHtmlElementOffset,
getSelectorStringFromElement,
htmlEncode,
htmlEntityDecode,
sanitizeHtmlToText,
Expand Down Expand Up @@ -130,6 +131,37 @@ describe('Service/domUtilies', () => {
});
});

describe('getSelectorStringFromElement() method', () => {
it('should return html element selector without classes when div is created without classes', () => {
const result = getSelectorStringFromElement(null);

expect(result).toBe('');
});

it('should return html element selector without classes when div is created without classes', () => {
const tmpDiv = document.createElement('div');
const result = getSelectorStringFromElement(tmpDiv);

expect(result).toBe('div');
});

it('should return html element selector with a single class name when exists', () => {
const tmpDiv = document.createElement('div');
tmpDiv.className = 'some-class'
const result = getSelectorStringFromElement(tmpDiv);

expect(result).toBe('div.some-class');
});

it('should return html element selector with multiple classes when exists', () => {
const tmpDiv = document.createElement('div');
tmpDiv.className = 'some-class other-class yet-more'
const result = getSelectorStringFromElement(tmpDiv);

expect(result).toBe('div.some-class.other-class.yet-more');
});
});

describe('htmlEncode method', () => {
it('should return a encoded HTML string', () => {
const result = htmlEncode(`<div class="color: blue">Something</div>`);
Expand Down
85 changes: 46 additions & 39 deletions packages/common/src/services/__tests__/filter.service.spec.ts

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions packages/common/src/services/domUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,14 @@ export function getHtmlElementOffset(element?: HTMLElement): HtmlElementPosition
return { top, left, bottom, right };
}

export function getSelectorStringFromElement(elm?: HTMLElement | null) {
let selector = '';
if (elm?.localName) {
selector = elm?.className ? `${elm.localName}.${Array.from(elm.classList).join('.')}` : elm.localName;
}
return selector;
}

export function findFirstElementAttribute(inputElm: Element | null | undefined, attributes: string[]): string | null {
if (inputElm) {
for (const attribute of attributes) {
Expand Down
8 changes: 6 additions & 2 deletions packages/common/src/services/filter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
SlickNamespace,
} from './../interfaces/index';
import { BackendUtilityService } from './backendUtility.service';
import { sanitizeHtmlToText, } from '../services/domUtilities';
import { getSelectorStringFromElement, sanitizeHtmlToText, } from '../services/domUtilities';
import { getDescendantProperty, mapOperatorByFieldType, } from './utilities';
import { SharedService } from './shared.service';
import { RxJsFacade, Subject } from './rxjsFacade';
Expand Down Expand Up @@ -669,6 +669,9 @@ export class FilterService {
if (columnFilter.operator) {
filter.operator = columnFilter.operator;
}
if (columnFilter.targetSelector) {
filter.targetSelector = columnFilter.targetSelector;
}
if (Array.isArray(filter.searchTerms) && filter.searchTerms.length > 0 && (!emptySearchTermReturnAllValues || filter.searchTerms[0] !== '')) {
currentFilters.push(filter);
}
Expand Down Expand Up @@ -1127,7 +1130,8 @@ export class FilterService {
columnId: colId,
columnDef,
parsedSearchTerms: [],
type: fieldType
type: fieldType,
targetSelector: getSelectorStringFromElement(event?.target as HTMLElement | undefined)
};
const inputSearchConditions = this.parseFormInputFilterConditions(searchTerms, colFilter);
colFilter.operator = operator || inputSearchConditions.operator || mapOperatorByFieldType(fieldType);
Expand Down
11 changes: 6 additions & 5 deletions packages/graphql/src/services/__tests__/graphql.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,15 +521,16 @@ describe('GraphqlService', () => {
const querySpy = jest.spyOn(service, 'buildQuery');
const resetSpy = jest.spyOn(service, 'resetPaginationOptions');
const mockColumn = { id: 'gender', field: 'gender' } as Column;
const mockColumnFilter = { columnDef: mockColumn, columnId: 'gender', operator: 'EQ', searchTerms: ['female'] } as ColumnFilter;
const mockColumnFilter = { columnDef: mockColumn, columnId: 'gender', operator: 'EQ', searchTerms: ['female'], targetSelector: 'div.some-classes' } as ColumnFilter;
const mockFilterChangedArgs = {
columnDef: mockColumn,
columnId: 'gender',
columnFilters: { gender: mockColumnFilter },
grid: gridStub,
operator: 'EQ',
searchTerms: ['female'],
shouldTriggerQuery: true
shouldTriggerQuery: true,
targetSelector: 'div.some-classes'
} as FilterChangedArgs;

service.init(serviceOptions, paginationOptions, gridStub);
Expand All @@ -539,7 +540,7 @@ describe('GraphqlService', () => {
expect(removeSpaces(query)).toBe(removeSpaces(expectation));
expect(querySpy).toHaveBeenCalled();
expect(resetSpy).toHaveBeenCalled();
expect(currentFilters).toEqual([{ columnId: 'gender', operator: 'EQ', searchTerms: ['female'] }]);
expect(currentFilters).toEqual([{ columnId: 'gender', operator: 'EQ', searchTerms: ['female'], targetSelector: 'div.some-classes' }]);
});

it('should return a query with a new filter when previous filters exists', () => {
Expand All @@ -550,7 +551,7 @@ describe('GraphqlService', () => {
const resetSpy = jest.spyOn(service, 'resetPaginationOptions');
const mockColumn = { id: 'gender', field: 'gender' } as Column;
const mockColumnName = { id: 'firstName', field: 'firstName' } as Column;
const mockColumnFilter = { columnDef: mockColumn, columnId: 'gender', operator: 'EQ', searchTerms: ['female'] } as ColumnFilter;
const mockColumnFilter = { columnDef: mockColumn, columnId: 'gender', operator: 'EQ', searchTerms: ['female'], targetSelector: 'div.some-classes' } as ColumnFilter;
const mockColumnFilterName = { columnDef: mockColumnName, columnId: 'firstName', operator: 'StartsWith', searchTerms: ['John'] } as ColumnFilter;
const mockFilterChangedArgs = {
columnDef: mockColumn,
Expand All @@ -570,7 +571,7 @@ describe('GraphqlService', () => {
expect(querySpy).toHaveBeenCalled();
expect(resetSpy).toHaveBeenCalled();
expect(currentFilters).toEqual([
{ columnId: 'gender', operator: 'EQ', searchTerms: ['female'] },
{ columnId: 'gender', operator: 'EQ', searchTerms: ['female'], targetSelector: 'div.some-classes' },
{ columnId: 'firstName', operator: 'StartsWith', searchTerms: ['John'] }
]);
});
Expand Down
3 changes: 3 additions & 0 deletions packages/graphql/src/services/graphql.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,9 @@ export class GraphqlService implements BackendService {
if (filter.operator) {
tmpFilter.operator = filter.operator;
}
if (filter.targetSelector) {
tmpFilter.targetSelector = filter.targetSelector;
}
if (Array.isArray(filter.searchTerms)) {
tmpFilter.searchTerms = filter.searchTerms;
}
Expand Down
19 changes: 11 additions & 8 deletions packages/odata/src/services/__tests__/grid-odata.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,8 @@ describe('GridOdataService', () => {
grid: gridStub,
operator: 'EQ',
searchTerms: ['female'],
shouldTriggerQuery: true
shouldTriggerQuery: true,
targetSelector: 'div.some-classes'
} as FilterChangedArgs;

service.init(serviceOptions, paginationOptions, gridStub);
Expand Down Expand Up @@ -322,7 +323,8 @@ describe('GridOdataService', () => {
grid: gridStub,
operator: 'EQ',
searchTerms: ['female'],
shouldTriggerQuery: true
shouldTriggerQuery: true,
targetSelector: 'div.some-classes'
} as FilterChangedArgs;

service.init(serviceOptions, paginationOptions, gridStub);
Expand Down Expand Up @@ -356,7 +358,8 @@ describe('GridOdataService', () => {
grid: gridStub,
operator: 'EQ',
searchTerms: ['female'],
shouldTriggerQuery: true
shouldTriggerQuery: true,
targetSelector: 'div.some-classes'
} as FilterChangedArgs;

service.init(serviceOptions, paginationOptions, gridStub);
Expand All @@ -375,8 +378,8 @@ describe('GridOdataService', () => {
const resetSpy = jest.spyOn(service, 'resetPaginationOptions');
const mockColumn = { id: 'gender', field: 'gender' } as Column;
const mockColumnName = { id: 'firstName', field: 'firstName' } as Column;
const mockColumnFilter = { columnDef: mockColumn, columnId: 'gender', operator: 'EQ', searchTerms: ['female'] } as ColumnFilter;
const mockColumnFilterName = { columnDef: mockColumnName, columnId: 'firstName', operator: 'StartsWith', searchTerms: ['John'] } as ColumnFilter;
const mockColumnFilter = { columnDef: mockColumn, columnId: 'gender', operator: 'EQ', searchTerms: ['female'], targetSelector: 'div.some-classes' } as ColumnFilter;
const mockColumnFilterName = { columnDef: mockColumnName, columnId: 'firstName', operator: 'StartsWith', searchTerms: ['John'], targetSelector: 'div.some-classes' } as ColumnFilter;
const mockFilterChangedArgs = {
columnDef: mockColumn,
columnId: 'gender',
Expand All @@ -395,8 +398,8 @@ describe('GridOdataService', () => {
expect(querySpy).toHaveBeenCalled();
expect(resetSpy).toHaveBeenCalled();
expect(currentFilters).toEqual([
{ columnId: 'gender', operator: 'EQ', searchTerms: ['female'] },
{ columnId: 'firstName', operator: 'StartsWith', searchTerms: ['John'] }
{ columnId: 'gender', operator: 'EQ', searchTerms: ['female'], targetSelector: 'div.some-classes' },
{ columnId: 'firstName', operator: 'StartsWith', searchTerms: ['John'], targetSelector: 'div.some-classes' }
]);
});
});
Expand Down Expand Up @@ -1798,7 +1801,7 @@ describe('GridOdataService', () => {
serviceOptions.enableCount = true;
service.init(serviceOptions, paginationOptions, gridStub);

service.postProcess({ '__count': 20 } );
service.postProcess({ '__count': 20 });

expect(paginationOptions.totalItems).toBe(20);
});
Expand Down
3 changes: 3 additions & 0 deletions packages/odata/src/services/grid-odata.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,9 @@ export class GridOdataService implements BackendService {
if (filter.operator) {
tmpFilter.operator = filter.operator;
}
if (filter.targetSelector) {
tmpFilter.targetSelector = filter.targetSelector;
}
if (Array.isArray(filter.searchTerms)) {
tmpFilter.searchTerms = filter.searchTerms;
}
Expand Down
2 changes: 1 addition & 1 deletion test/cypress/e2e/example09.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ describe('Example 09 - OData Grid', { retries: 1 }, () => {

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', operator: 'Contains', searchTerms: ['x'] }], type: 'filter' });
expect(win.console.log).to.be.calledWith('Client sample, Grid State changed:: ', { newValues: [{ columnId: 'name', operator: 'Contains', searchTerms: ['x'], targetSelector: 'input.form-control.filter-name.compound-input' }], type: 'filter' });
// expect(win.console.log).to.be.calledWith('Client sample, Grid State changed:: ', { newValues: { pageNumber: 1, pageSize: 10 }, type: 'pagination' });
});
});
Expand Down
2 changes: 1 addition & 1 deletion test/cypress/e2e/example15.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ describe('Example 15 - OData Grid using RxJS', { retries: 1 }, () => {

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', operator: 'Contains', searchTerms: ['x'] }], type: 'filter' });
expect(win.console.log).to.be.calledWith('Client sample, Grid State changed:: ', { newValues: [{ columnId: 'name', operator: 'Contains', searchTerms: ['x'], targetSelector: 'input.form-control.filter-name.compound-input' }], 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 a25791a

Please sign in to comment.