diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example10.ts b/examples/vite-demo-vanilla-bundle/src/examples/example10.ts index d00cc2999..c65a19539 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example10.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example10.ts @@ -60,6 +60,7 @@ export default class Example10 { // this._bindingEventService.bind(gridContainerElm, 'onbeforeexporttoexcel', () => console.log('onBeforeExportToExcel')); // this._bindingEventService.bind(gridContainerElm, 'onafterexporttoexcel', () => console.log('onAfterExportToExcel')); this.sgb = new Slicker.GridBundle(gridContainerElm, this.columnDefinitions, { ...ExampleGridOptions, ...this.gridOptions }, this.dataset); + this._bindingEventService.bind(gridContainerElm, 'ongridstatechanged', this.handleOnGridStateChanged.bind(this)); document.body.classList.add('material-theme'); } @@ -294,9 +295,11 @@ export default class Example10 { this.sgb?.paginationService?.goToLastPage(); } - /** Dispatched event of a Grid State Changed event */ - gridStateChanged(gridStateChanges: GridStateChange) { - console.log('GraphQL sample, Grid State changed:: ', gridStateChanges); + handleOnGridStateChanged(event) { + if (event?.detail) { + const gridStateChanges: GridStateChange = event.detail; + console.log('Grid State changed:: ', gridStateChanges.change); + } } saveCurrentGridState() { diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example12.ts b/examples/vite-demo-vanilla-bundle/src/examples/example12.ts index ad44b1a59..3a007dcd9 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example12.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example12.ts @@ -639,7 +639,7 @@ export default class Example12 { } handleOnGridStateChanged(event) { - // console.log('handleOnGridStateChanged', event?.detail ?? '') + // console.log('handleOnGridStateChanged', event?.detail ?? ''); const gridState = event?.detail?.gridState; if (Array.isArray(gridState?.rowSelection.dataContextIds)) { this.isMassSelectionDisabled = gridState.rowSelection.dataContextIds.length === 0; diff --git a/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts b/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts index f323cbd05..c78936a4a 100644 --- a/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts +++ b/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts @@ -273,6 +273,7 @@ describe('CompoundDateFilter', () => { filterArguments.searchTerms = ['2000-01-01']; mockColumn.filter!.operator = '<='; const clearSpy = jest.spyOn(filter, 'clear'); + const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); filter.show(); @@ -285,6 +286,7 @@ describe('CompoundDateFilter', () => { filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { key: 'Backspace', bubbles: true, cancelable: true })); expect(clearSpy).toHaveBeenCalled(); expect(filterInputElm.value).toBe(''); + expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '', searchTerms: null, shouldTriggerQuery: true }); }); it('should create the input filter with a default search terms when passed as a filter argument', () => { diff --git a/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts b/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts index 4035d0ec2..95a090705 100644 --- a/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts +++ b/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts @@ -196,6 +196,26 @@ describe('DateRangeFilter', () => { expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: 'RangeExclusive', searchTerms: ['2001-01-02', '2001-01-13'], shouldTriggerQuery: true }); }); + it('should clear picker when pressing Backspace key', () => { + filterArguments.searchTerms = ['2001-01-02', '2001-01-13']; + mockColumn.filter!.operator = 'RangeInclusive'; + const clearSpy = jest.spyOn(filter, 'clear'); + const spyCallback = jest.spyOn(filterArguments, 'callback'); + + filter.init(filterArguments); + filter.show(); + const filterInputElm = divContainer.querySelector('.date-picker.search-filter.filter-finish input.date-picker') as HTMLInputElement; + const calendarElm = document.body.querySelector('.vanilla-calendar') as HTMLDivElement; + + expect(calendarElm).toBeTruthy(); + expect(filterInputElm.value).toBe('2001-01-02 — 2001-01-13'); + + filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { key: 'Backspace', bubbles: true, cancelable: true })); + expect(clearSpy).toHaveBeenCalled(); + expect(filterInputElm.value).toBe(''); + expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'RangeInclusive', searchTerms: [], shouldTriggerQuery: true }); + }); + it('should create the input filter with a default search terms when passed as a filter argument', () => { const selectedDates = ['2001-01-02', '2001-01-13']; filterArguments.searchTerms = ['2001-01-02', '2001-01-13']; diff --git a/packages/common/src/filters/dateFilter.ts b/packages/common/src/filters/dateFilter.ts index 1681b8c7d..87a5a21c1 100644 --- a/packages/common/src/filters/dateFilter.ts +++ b/packages/common/src/filters/dateFilter.ts @@ -143,23 +143,32 @@ export class DateFilter implements Filter { // clear date picker + compound operator when Backspace is pressed this._bindEventService.bind(this._dateInputElm, 'keydown', ((e: KeyboardEvent) => { if (e.key === 'Backspace') { - this.clear(true); + this.clear(true, false); // clear value but trigger a value change event } }) as EventListener); } /** Clear the filter value */ - clear(shouldTriggerQuery = true) { + clear(shouldTriggerQuery = true, shouldTriggerClearEvent = true) { if (this.calendarInstance) { - this._clearFilterTriggered = true; + // in some cases we don't want to trigger a Clear event, like a Backspace, we want to clear the value but trigger a value change instead + this._clearFilterTriggered = shouldTriggerClearEvent; this._shouldTriggerQuery = shouldTriggerQuery; + this._currentValue = ''; this.searchTerms = []; + this._currentDateStrings = []; if (this._selectOperatorElm) { this._selectOperatorElm.selectedIndex = 0; } if (this.calendarInstance.input) { this.calendarInstance.settings.selected.dates = []; this._dateInputElm.value = ''; + this.calendarInstance.update({ + dates: true, + month: true, + year: true, + time: true, + }); } } this.onTriggerEvent(new Event('keyup')); diff --git a/test/cypress/e2e/example07.cy.ts b/test/cypress/e2e/example07.cy.ts index 7dc0c15bc..37774c478 100644 --- a/test/cypress/e2e/example07.cy.ts +++ b/test/cypress/e2e/example07.cy.ts @@ -170,7 +170,7 @@ describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => { // change Finish date cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(7)`).should('contain', '2009-01-05').click(); - cy.get('.vanilla-calendar:visible .vanilla-calendar-day').contains('22').click('bottom', { force: true }); + cy.get('.vanilla-calendar:visible .vanilla-calendar-day:contains("22"):visible').first().click(); cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(7)`).should('contain', '2009-01-22'); cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left') @@ -288,7 +288,7 @@ describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => { // change Finish date cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(7)`).should('contain', '2009-01-05').click(); - cy.get('.vanilla-calendar:visible .vanilla-calendar-day').contains('22').click('bottom', { force: true }); + cy.get('.vanilla-calendar:visible .vanilla-calendar-day:contains("22"):visible').first().click(); cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(7)`).should('contain', '2009-01-22'); cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(10)`).should('contain', 'Task 0000'); diff --git a/test/cypress/e2e/example10.cy.ts b/test/cypress/e2e/example10.cy.ts index 4b869545b..94a1ffd37 100644 --- a/test/cypress/e2e/example10.cy.ts +++ b/test/cypress/e2e/example10.cy.ts @@ -8,6 +8,13 @@ const presetLowestDay = format(addDay(new Date(), -2), 'YYYY-MM-DD'); const presetHighestDay = format(addDay(new Date(), 20), 'YYYY-MM-DD'); describe('Example 10 - GraphQL Grid', () => { + beforeEach(() => { + // create a console.log spy for later use + cy.window().then((win) => { + cy.spy(win.console, 'log'); + }); + }); + it('should display Example title', () => { cy.visit(`${Cypress.config('baseUrl')}/example10`); cy.get('h3').should('contain', 'Example 10 - Grid with GraphQL Backend Service'); @@ -800,4 +807,51 @@ describe('Example 10 - GraphQL Grid', () => { }); }); }); + + describe('Grid State Changes', () => { + it('should re-initialize grid for offset pagination', () => { + cy.get('[data-test=offset]').click(); + cy.get('[data-test="reset-presets"]').click(); + + // the page number input should be back to input + cy.get('[data-test=page-number-input]').should('exist') + .invoke('val') + .then(text => expect(text).to.eq('2')); + }); + + it('should have GraphQL query back to defined Grid Presets', () => { + cy.get('[data-test=status]').should('contain', 'finished'); + + cy.get('[data-test=graphql-query-result]') + .should(($span) => { + const text = removeSpaces($span.text()); // remove all white spaces + expect(text).to.eq(removeSpaces(`query{users(first:20,offset:20, + orderBy:[{field:"name",direction:ASC},{field:"company",direction:DESC}], + filterBy:[ + {field:"gender",operator:EQ,value:"male"}, + {field:"name",operator:StartsWith,value:"Joh"},{field:"name",operator:EndsWith,value:"oe"}, + {field:"company",operator:IN,value:"xyz"},{field:"finish",operator:GE,value:"${presetLowestDay}"},{field:"finish",operator:LE,value:"${presetHighestDay}"} + ],locale:"en",userId:123){ + totalCount,nodes{id,name,gender,company,billing{address{street,zip}},finish}}}`)); + }); + }); + + it('should expect 1 event change Finish filter to empty and 1 event for the pagination change', () => { + cy.get('.search-filter.filter-finish').click(); + cy.wait(20); + cy.get('.search-filter.filter-finish input.date-picker').type('{backspace}', { force: true }); + + cy.window().then((win) => { + expect(win.console.log).to.have.callCount(2); + expect(win.console.log).to.be.calledWith('Grid State changed:: ', { + newValues: [ + { columnId: 'gender', operator: 'EQ', searchTerms: ['male'] }, + { columnId: 'name', operator: 'StartsWithEndsWith', searchTerms: ['Joh*oe'] }, + { columnId: 'company', operator: 'IN', searchTerms: ['xyz'] }, + ], type: 'filter' + }); + expect(win.console.log).to.be.calledWith('Grid State changed:: ', { newValues: { pageNumber: 1, pageSize: 20 }, type: 'pagination' }); + }); + }); + }); }); diff --git a/test/cypress/e2e/example11.cy.ts b/test/cypress/e2e/example11.cy.ts index 7a52b5e70..c18d3636d 100644 --- a/test/cypress/e2e/example11.cy.ts +++ b/test/cypress/e2e/example11.cy.ts @@ -169,7 +169,7 @@ describe('Example 11 - Batch Editing', () => { cy.get('[data-test=undo-last-edit-btn]').click(); cy.get('.vanilla-calendar') - .should('not.exist'); + .should('not.be.visible'); cy.get('.unsaved-editable-field') .should('have.length', 11);