Skip to content

Commit f61285d

Browse files
committed
fix(paging): don't reset page 1 after manually adding items to grid
- manually adding items (via the grid service addItem()) shouldn't reset pagination to page 1 - completely change how we pass the options to the child pagination component - no longer relying on the entire grid option to be passed to the pagination (which was error pron) - now passes only the essential options required by the pagination
1 parent c953a23 commit f61285d

10 files changed

+198
-161
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
<div id="slickGridContainer-{{gridId}}" class="gridPane" [style.width]="gridWidthString">
2-
<div attr.id='{{gridId}}' class="slickgrid-container" style="width: 100%" [style.height]="gridHeightString">
3-
</div>
2+
<div attr.id='{{gridId}}' class="slickgrid-container" style="width: 100%" [style.height]="gridHeightString">
3+
</div>
44

5-
<slick-pagination id="slickPagingContainer-{{gridId}}"
6-
*ngIf="showPagination"
7-
(onPaginationChanged)="paginationChanged($event)"
8-
[dataView]="dataView"
9-
[gridPaginationOptions]="gridPaginationOptions">
10-
</slick-pagination>
5+
<slick-pagination id="slickPagingContainer-{{gridId}}"
6+
*ngIf="showPagination"
7+
(onPaginationChanged)="paginationChanged($event)"
8+
[enableTranslate]="gridOptions.enableTranslate"
9+
[dataView]="dataView"
10+
[grid]="grid"
11+
[options]="paginationOptions"
12+
[locales]="locales"
13+
[totalItems]="totalItems"
14+
[backendServiceApi]="backendServiceApi">
15+
</slick-pagination>
1116
</div>

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

+27-17
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,24 @@ import 'slickgrid/slick.grid';
77
import 'slickgrid/slick.dataview';
88

99
// ...then everything else...
10-
import { AfterViewInit, Component, ElementRef, EventEmitter, Inject, Injectable, Input, Output, OnDestroy, OnInit, Optional } from '@angular/core';
10+
import { AfterViewInit, Component, ElementRef, EventEmitter, Inject, Input, Output, OnDestroy, OnInit, Optional } from '@angular/core';
1111
import { TranslateService } from '@ngx-translate/core';
12+
13+
import { Constants } from '../constants';
1214
import { GlobalGridOptions } from './../global-grid-options';
1315
import { titleCase, unsubscribeAllObservables } from './../services/utilities';
1416
import { executeBackendProcessesCallback, onBackendError } from '../services/backend-utilities';
1517
import {
1618
AngularGridInstance,
19+
BackendServiceApi,
1720
BackendServiceOption,
1821
Column,
1922
ExtensionName,
2023
GraphqlResult,
2124
GridOption,
2225
GridStateChange,
2326
GridStateType,
27+
Locale,
2428
Pagination,
2529
} from './../models/index';
2630
import { FilterFactory } from '../filters/filterFactory';
@@ -63,7 +67,6 @@ declare var $: any;
6367

6468
const slickgridEventPrefix = 'sg';
6569

66-
@Injectable()
6770
@Component({
6871
selector: 'angular-slickgrid',
6972
templateUrl: './angular-slickgrid.component.html',
@@ -108,12 +111,15 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
108111
private _hideHeaderRowAfterPageLoad = false;
109112
dataView: any;
110113
grid: any;
111-
gridPaginationOptions: GridOption;
112114
gridHeightString: string;
113115
gridWidthString: string;
114116
groupingDefinition: any = {};
115117
groupItemMetadataProvider: any;
118+
backendServiceApi: BackendServiceApi;
119+
locales: Locale;
120+
paginationOptions: Pagination;
116121
showPagination = false;
122+
totalItems = 0;
117123
isGridInitialized = false;
118124
subscriptions: Subscription[] = [];
119125

@@ -234,6 +240,9 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
234240
// make sure the dataset is initialized (if not it will throw an error that it cannot getLength of null)
235241
this._dataset = this._dataset || [];
236242
this.gridOptions = this.mergeGridOptions(this.gridOptions);
243+
this.paginationOptions = this.gridOptions.pagination;
244+
this.locales = this.gridOptions && this.gridOptions.locales || Constants.locales;
245+
this.backendServiceApi = this.gridOptions && this.gridOptions.backendServiceApi;
237246
this.createBackendApiInternalPostProcessCallback(this.gridOptions);
238247

239248
if (!this.customDataView) {
@@ -564,10 +573,10 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
564573
try {
565574
// the processes can be Observables (like HttpClient) or Promises
566575
if (process instanceof Promise && process.then) {
567-
process.then((processResult: GraphqlResult | any) => executeBackendProcessesCallback(startTime, processResult, backendApi, this.gridOptions));
576+
process.then((processResult: GraphqlResult | any) => executeBackendProcessesCallback(startTime, processResult, backendApi, this.gridOptions.pagination.totalItems));
568577
} else if (isObservable(process)) {
569578
process.subscribe(
570-
(processResult: GraphqlResult | any) => executeBackendProcessesCallback(startTime, processResult, backendApi, this.gridOptions),
579+
(processResult: GraphqlResult | any) => executeBackendProcessesCallback(startTime, processResult, backendApi, this.gridOptions.pagination.totalItems),
571580
(error: any) => onBackendError(error, backendApi)
572581
);
573582
}
@@ -665,24 +674,25 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
665674
this.grid.render();
666675
}
667676

668-
if (this.gridOptions.backendServiceApi) {
677+
if (this.gridOptions && this.gridOptions.backendServiceApi && this.gridOptions.pagination) {
669678
// do we want to show pagination?
670679
// if we have a backendServiceApi and the enablePagination is undefined, we'll assume that we do want to see it, else get that defined value
671680
this.showPagination = ((this.gridOptions.backendServiceApi && this.gridOptions.enablePagination === undefined) ? true : this.gridOptions.enablePagination) || false;
672681

673-
// before merging the grid options, make sure that it has the totalItems count
674-
// once we have that, we can merge and pass all these options to the pagination component
675-
if (!this.gridOptions.pagination) {
676-
this.gridOptions.pagination = (this.gridOptions.pagination) ? this.gridOptions.pagination : undefined;
677-
}
678-
if (this.gridOptions.pagination && totalCount !== undefined) {
679-
this.gridOptions.pagination.totalItems = totalCount;
680-
}
681682
if (this.gridOptions.presets && this.gridOptions.presets.pagination && this.gridOptions.pagination) {
682-
this.gridOptions.pagination.pageSize = this.gridOptions.presets.pagination.pageSize;
683-
this.gridOptions.pagination.pageNumber = this.gridOptions.presets.pagination.pageNumber;
683+
this.paginationOptions.pageSize = this.gridOptions.presets.pagination.pageSize;
684+
this.paginationOptions.pageNumber = this.gridOptions.presets.pagination.pageNumber;
684685
}
685-
this.gridPaginationOptions = this.mergeGridOptions(this.gridOptions);
686+
687+
// when we have a totalCount use it, else we'll take it from the pagination object
688+
// only update the total items if it's different to avoid refreshing the UI
689+
const totalRecords = totalCount !== undefined ? totalCount : this.gridOptions.pagination.totalItems;
690+
if (totalRecords !== this.totalItems) {
691+
this.totalItems = totalRecords;
692+
}
693+
} else {
694+
// without backend service, we'll assume the total of items is the dataset size
695+
this.totalItems = dataset.length;
686696
}
687697

688698
// resize the grid inside a slight timeout, in case other DOM element changed prior to the resize (like a filter/pagination changed)

src/app/modules/angular-slickgrid/components/slick-pagination.component.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div class="slick-pagination" *ngIf="pager">
1+
<div class="slick-pagination" *ngIf="pager && options">
22
<div class="slick-pagination-nav">
33
<nav aria-label="Page navigation">
44
<ul class="pagination">
@@ -41,7 +41,7 @@
4141
</div>
4242
<span class="slick-pagination-settings">
4343
<select id="items-per-page-label" [value]="pager?.itemsPerPage" (change)="changeItemPerPage($event)">
44-
<option value="{{pageSize}}" *ngFor="let pageSize of pager?.availablePageSizes;">{{pageSize}}</option>
44+
<option value="{{pageSize}}" *ngFor="let pageSize of options.pageSizes">{{pageSize}}</option>
4545
</select>
4646
<span>{{textItemsPerPage}}</span>,
4747
<span class="slick-pagination-count">

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

+22-26
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,39 @@ import { AfterViewInit, Component, EventEmitter, Injectable, Input, OnDestroy, O
22
import { TranslateService } from '@ngx-translate/core';
33
import { Subscription } from 'rxjs';
44

5-
import { Constants } from '../constants';
6-
import { GridOption, Locale, Pager, Pagination } from './../models/index';
5+
import { BackendServiceApi, Locale, Pager, Pagination } from './../models/index';
76
import { PaginationService } from '../services/pagination.service';
87
import { unsubscribeAllObservables } from '../services/utilities';
98

109
@Component({
1110
selector: 'slick-pagination',
1211
templateUrl: './slick-pagination.component.html'
1312
})
14-
@Injectable()
1513
export class SlickPaginationComponent implements AfterViewInit, OnDestroy {
16-
private _gridPaginationOptions: GridOption;
1714
private _isFirstRender = true;
18-
private _locales: Locale;
1915
private _pager: Pager;
16+
private _totalItems: number;
2017
private subscriptions: Subscription[] = [];
2118

2219
@Output() onPaginationChanged = new EventEmitter<Pagination>();
20+
@Input() enableTranslate: boolean;
21+
@Input() options: Pagination;
2322
@Input() dataView: any;
23+
@Input() locales: Locale;
24+
@Input() backendServiceApi: BackendServiceApi;
2425
@Input()
25-
set gridPaginationOptions(gridPaginationOptions: GridOption) {
26-
this._gridPaginationOptions = gridPaginationOptions;
27-
if (this._isFirstRender || !gridPaginationOptions || !gridPaginationOptions.pagination || (gridPaginationOptions.pagination.totalItems !== this.pager.totalItems)) {
28-
this.refreshPagination();
29-
this._isFirstRender = false;
26+
set totalItems(total: number) {
27+
if (this._isFirstRender || this._totalItems === undefined) {
28+
this._isFirstRender = true;
29+
}
30+
this._totalItems = total;
31+
this._isFirstRender = false;
32+
if (this.paginationService) {
33+
this.paginationService.totalItems = total;
3034
}
3135
}
32-
get gridPaginationOptions(): GridOption {
33-
return this._gridPaginationOptions;
36+
get totalItems(): number {
37+
return this._totalItems;
3438
}
3539
@Input() grid: any;
3640

@@ -44,11 +48,11 @@ export class SlickPaginationComponent implements AfterViewInit, OnDestroy {
4448
constructor(private paginationService: PaginationService, @Optional() private translate: TranslateService) {
4549
// translate all the text using ngx-translate or custom locales
4650
if (translate && translate.onLangChange) {
47-
this.subscriptions.push(this.translate.onLangChange.subscribe(() => this.translateAllUiTexts(this._locales)));
51+
this.subscriptions.push(this.translate.onLangChange.subscribe(() => this.translateAllUiTexts(this.locales)));
4852
}
4953

5054
// translate all the text using ngx-translate or custom locales
51-
this.paginationService.onPaginationRefreshed.subscribe(() => this.translateAllUiTexts(this._locales));
55+
this.paginationService.onPaginationRefreshed.subscribe(() => this.translateAllUiTexts(this.locales));
5256

5357
this.paginationService.onPaginationChanged.subscribe(pager => {
5458
this._pager = pager;
@@ -74,13 +78,12 @@ export class SlickPaginationComponent implements AfterViewInit, OnDestroy {
7478
}
7579

7680
ngAfterViewInit() {
77-
if (this._gridPaginationOptions && this._gridPaginationOptions.enableTranslate && !this.translate) {
81+
if (this.enableTranslate && !this.translate) {
7882
throw new Error('[Angular-Slickgrid] requires "ngx-translate" to be installed and configured when the grid option "enableTranslate" is enabled.');
7983
}
80-
// get locales provided by user in forRoot or else use default English locales via the Constants
81-
this._locales = this._gridPaginationOptions && this._gridPaginationOptions.locales || Constants.locales;
82-
83-
this.paginationService.init(this.grid, this.dataView, this._gridPaginationOptions);
84+
// Angular throws the infamous "ExpressionChangedAfterItHasBeenCheckedError"
85+
// none of the code refactoring worked to go over the error expect adding a delay, so we'll keep that for now
86+
setTimeout(() => this.paginationService.init(this.grid, this.dataView, this.options, this.backendServiceApi));
8487
}
8588

8689
changeToFirstPage(event: any) {
@@ -123,13 +126,6 @@ export class SlickPaginationComponent implements AfterViewInit, OnDestroy {
123126
this.subscriptions = unsubscribeAllObservables(this.subscriptions);
124127
}
125128

126-
refreshPagination() {
127-
if (this.paginationService) {
128-
this.paginationService.gridPaginationOptions = this._gridPaginationOptions;
129-
this.paginationService.refreshPagination();
130-
}
131-
}
132-
133129
// --
134130
// private functions
135131
// --------------------

src/app/modules/angular-slickgrid/services/__tests__/backend-utilities.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ describe('backend-utilities', () => {
1616
const now = new Date();
1717
gridOptionMock.backendServiceApi.internalPostProcess = jest.fn();
1818
const spy = jest.spyOn(gridOptionMock.backendServiceApi, 'internalPostProcess');
19-
executeBackendProcessesCallback(now, { data: {} }, gridOptionMock.backendServiceApi, gridOptionMock);
19+
executeBackendProcessesCallback(now, { data: {} }, gridOptionMock.backendServiceApi, 0);
2020

2121
expect(spy).toHaveBeenCalled();
2222
});
@@ -46,7 +46,7 @@ describe('backend-utilities', () => {
4646
gridOptionMock.pagination = { totalItems: 1, pageSizes: [10, 25], pageSize: 10 };
4747

4848
const spy = jest.spyOn(gridOptionMock.backendServiceApi, 'postProcess');
49-
executeBackendProcessesCallback(now, mockResult, gridOptionMock.backendServiceApi, gridOptionMock);
49+
executeBackendProcessesCallback(now, mockResult, gridOptionMock.backendServiceApi, 1);
5050

5151
expect(spy).toHaveBeenCalledWith(expectaction);
5252
});

0 commit comments

Comments
 (0)