diff --git a/src/app/examples/grid-odata.component.html b/src/app/examples/grid-odata.component.html index 26f4062df..a9f9454a9 100644 --- a/src/app/examples/grid-odata.component.html +++ b/src/app/examples/grid-odata.component.html @@ -31,16 +31,16 @@

{{title}}

@@ -55,8 +55,12 @@

{{title}}

- + diff --git a/src/app/examples/grid-odata.component.ts b/src/app/examples/grid-odata.component.ts index 669bfb51d..612affc72 100644 --- a/src/app/examples/grid-odata.component.ts +++ b/src/app/examples/grid-odata.component.ts @@ -12,6 +12,7 @@ import { OdataOption, OdataServiceApi, OperatorType, + Pagination, } from './../modules/angular-slickgrid'; const defaultPageSize = 20; @@ -43,6 +44,7 @@ export class GridOdataComponent implements OnInit { gridOptions: GridOption; dataset = []; metrics: Metrics; + paginationOptions: Pagination; isCountEnabled = true; odataVersion = 2; @@ -139,11 +141,10 @@ export class GridOdataComponent implements OnInit { if (this.isCountEnabled) { countPropName = (this.odataVersion === 4) ? '@odata.count' : 'odata.count'; } - this.gridOptions.pagination.totalItems = data[countPropName]; + this.paginationOptions = { ...this.gridOptions.pagination, totalItems: data[countPropName] }; if (this.metrics) { this.metrics.totalItemCount = data[countPropName]; } - this.gridOptions = Object.assign({}, this.gridOptions); // once pagination totalItems is filled, we can update the dataset this.dataset = data['items']; diff --git a/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid-constructor.spec.ts b/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid-constructor.spec.ts index 48259aa7d..91544b5d1 100644 --- a/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid-constructor.spec.ts +++ b/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid-constructor.spec.ts @@ -126,6 +126,7 @@ const paginationServiceStub = { totalItems: 0, init: jest.fn(), dispose: jest.fn(), + updateTotalItems: jest.fn(), onPaginationVisibilityChanged: new Subject(), onPaginationChanged: new Subject(), } as unknown as PaginationService; @@ -1249,6 +1250,29 @@ describe('Angular-Slickgrid Custom Component instantiated via Constructor', () = component.destroy(); }); + it('should merge paginationOptions when some already exist', () => { + const mockPagination = { pageSize: 2, pageSizes: [] }; + const paginationSrvSpy = jest.spyOn(paginationServiceStub, 'updateTotalItems'); + + component.ngAfterViewInit(); + component.paginationOptions = mockPagination; + + expect(component.paginationOptions).toEqual({ ...mockPagination, totalItems: 0 }); + expect(paginationSrvSpy).toHaveBeenCalledWith(0, true); + }); + + it('should set brand new paginationOptions when none previously exist', () => { + const mockPagination = { pageSize: 2, pageSizes: [], totalItems: 1 }; + const paginationSrvSpy = jest.spyOn(paginationServiceStub, 'updateTotalItems'); + + component.ngAfterViewInit(); + component.paginationOptions = undefined; + component.paginationOptions = mockPagination; + + expect(component.paginationOptions).toEqual(mockPagination); + expect(paginationSrvSpy).toHaveBeenNthCalledWith(2, 1, true); + }); + it('should call trigger a gridStage change event when pagination change is triggered', () => { const mockPagination = { pageNumber: 2, pageSize: 20 } as Pagination; const spy = jest.spyOn(gridStateServiceStub.onGridStateChanged, 'next'); diff --git a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts index 9b70d02eb..a82599f46 100644 --- a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts +++ b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts @@ -132,6 +132,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn private _isDatasetInitialized = false; private _isPaginationInitialized = false; private _isLocalGrid = true; + private _paginationOptions: Pagination | undefined; private slickEmptyWarning: SlickEmptyWarningComponent; dataView: any | null; grid: any | null; @@ -143,7 +144,6 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn customFooterOptions: CustomFooterOption; locales: Locale; metrics: Metrics; - paginationOptions: Pagination; showCustomFooter = false; showPagination = false; totalItems = 0; @@ -168,6 +168,20 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn @Input() gridId: string; @Input() gridOptions: GridOption; + @Input() + get paginationOptions(): Pagination | undefined { + return this._paginationOptions; + } + set paginationOptions(options: Pagination | undefined) { + if (options && this._paginationOptions) { + this._paginationOptions = { ...this._paginationOptions, ...options }; + } else { + this._paginationOptions = options; + } + this.gridOptions.pagination = options; + this.paginationService.updateTotalItems(options && options.totalItems || 0, true); + } + @Input() set gridHeight(height: number) { this._fixedHeight = height; @@ -435,7 +449,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn this.showPagination = (this.gridOptions && (this.gridOptions.enablePagination || (this.gridOptions.backendServiceApi && this.gridOptions.enablePagination === undefined))) ? true : false; if (this.gridOptions && this.gridOptions.backendServiceApi && this.gridOptions.pagination) { - const paginationOptions = this.setPaginationOptionsWhenPresetDefined(this.gridOptions, this.paginationOptions); + const paginationOptions = this.setPaginationOptionsWhenPresetDefined(this.gridOptions, this._paginationOptions); // when we have a totalCount use it, else we'll take it from the pagination object // only update the total items if it's different to avoid refreshing the UI const totalRecords = totalCount !== undefined ? totalCount : (this.gridOptions && this.gridOptions.pagination && this.gridOptions.pagination.totalItems); @@ -783,7 +797,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn // make sure the dataset is initialized (if not it will throw an error that it cannot getLength of null) this._dataset = this._dataset || []; this.gridOptions = this.mergeGridOptions(this.gridOptions); - this.paginationOptions = this.gridOptions.pagination; + this._paginationOptions = this.gridOptions.pagination; this.locales = this.gridOptions && this.gridOptions.locales || Constants.locales; this.backendServiceApi = this.gridOptions && this.gridOptions.backendServiceApi; this.createBackendApiInternalPostProcessCallback(this.gridOptions); @@ -1007,14 +1021,14 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn private loadLocalGridPagination() { if (this.gridOptions) { this.totalItems = Array.isArray(this.dataset) ? this.dataset.length : 0; - if (this.paginationOptions && this.dataView && this.dataView.getPagingInfo) { + if (this._paginationOptions && this.dataView && this.dataView.getPagingInfo) { const slickPagingInfo = this.dataView.getPagingInfo() || {}; - if (slickPagingInfo.hasOwnProperty('totalRows') && this.paginationOptions.totalItems !== slickPagingInfo.totalRows) { + if (slickPagingInfo.hasOwnProperty('totalRows') && this._paginationOptions.totalItems !== slickPagingInfo.totalRows) { this.totalItems = slickPagingInfo.totalRows; } } - this.paginationOptions.totalItems = this.totalItems; - const paginationOptions = this.setPaginationOptionsWhenPresetDefined(this.gridOptions, this.paginationOptions); + this._paginationOptions.totalItems = this.totalItems; + const paginationOptions = this.setPaginationOptionsWhenPresetDefined(this.gridOptions, this._paginationOptions); this.initializePaginationService(paginationOptions); } } diff --git a/src/app/modules/angular-slickgrid/services/pagination.service.ts b/src/app/modules/angular-slickgrid/services/pagination.service.ts index ae55d767d..2a4ac25b3 100644 --- a/src/app/modules/angular-slickgrid/services/pagination.service.ts +++ b/src/app/modules/angular-slickgrid/services/pagination.service.ts @@ -95,9 +95,7 @@ export class PaginationService { if (this._isLocalGrid && this.dataView) { this._eventHandler.subscribe(this.dataView.onPagingInfoChanged, (e, pagingInfo) => { if (this._totalItems !== pagingInfo.totalRows) { - this._totalItems = pagingInfo.totalRows; - this._paginationOptions.totalItems = this._totalItems; - this.refreshPagination(false, false); + this.updateTotalItems(pagingInfo.totalRows); } }); dataView.setRefreshHints({ isFilterUnchanged: true }); @@ -367,6 +365,14 @@ export class PaginationService { // private functions // -------------------- + updateTotalItems(totalItems: number, triggerChangedEvent = false) { + this._totalItems = totalItems; + if (this._paginationOptions) { + this._paginationOptions.totalItems = totalItems; + this.refreshPagination(false, triggerChangedEvent); + } + } + /** * When item is added or removed, we will refresh the numbers on the pagination however we won't trigger a backend change * This will have a side effect though, which is that the "To" count won't be matching the "items per page" count, diff --git a/test/cypress/integration/example05.spec.js b/test/cypress/integration/example05.spec.js index e31b50d10..ca030eb7f 100644 --- a/test/cypress/integration/example05.spec.js +++ b/test/cypress/integration/example05.spec.js @@ -516,6 +516,9 @@ describe('Example 5 - OData Grid', () => { // wait for the query to finish cy.get('[data-test=status]').should('contain', 'done'); + + cy.get('.slick-empty-data-warning:visible') + .contains('No data to display.'); }); it('should display page 0 of 0 but hide pagination from/to numbers when filtered data "xy" returns an empty dataset', () => { @@ -554,6 +557,10 @@ describe('Example 5 - OData Grid', () => { // wait for the query to finish cy.get('[data-test=status]').should('contain', 'done'); + cy.get('.slick-empty-data-warning') + .contains('No data to display.') + .should('not.be.visible'); + 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' });