Skip to content

feat(paginator): expose previousPageIndex inside PageEvent #10759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 42 additions & 29 deletions src/lib/paginator/paginator.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {async, ComponentFixture, TestBed, inject} from '@angular/core/testing';
import {MatPaginatorModule} from './index';
import {MatPaginator, PageEvent} from './paginator';
import {MatPaginator} from './paginator';
import {Component, ViewChild} from '@angular/core';
import {MatPaginatorIntl} from './paginator-intl';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
Expand Down Expand Up @@ -111,7 +111,10 @@ describe('MatPaginator', () => {
dispatchMouseEvent(getNextButton(fixture), 'click');

expect(paginator.pageIndex).toBe(1);
expect(component.latestPageEvent ? component.latestPageEvent.pageIndex : null).toBe(1);
expect(component.pageEvent).toHaveBeenCalledWith(jasmine.objectContaining({
previousPageIndex: 0,
pageIndex: 1
}));
});

it('should be able to go to the previous page', () => {
Expand All @@ -122,7 +125,10 @@ describe('MatPaginator', () => {
dispatchMouseEvent(getPreviousButton(fixture), 'click');

expect(paginator.pageIndex).toBe(0);
expect(component.latestPageEvent ? component.latestPageEvent.pageIndex : null).toBe(0);
expect(component.pageEvent).toHaveBeenCalledWith(jasmine.objectContaining({
previousPageIndex: 1,
pageIndex: 0
}));
});

});
Expand Down Expand Up @@ -163,7 +169,10 @@ describe('MatPaginator', () => {
dispatchMouseEvent(getLastButton(fixture), 'click');

expect(paginator.pageIndex).toBe(9);
expect(component.latestPageEvent ? component.latestPageEvent.pageIndex : null).toBe(9);
expect(component.pageEvent).toHaveBeenCalledWith(jasmine.objectContaining({
previousPageIndex: 0,
pageIndex: 9
}));
});

it('should be able to go to the first page via the first page button', () => {
Expand All @@ -174,7 +183,10 @@ describe('MatPaginator', () => {
dispatchMouseEvent(getFirstButton(fixture), 'click');

expect(paginator.pageIndex).toBe(0);
expect(component.latestPageEvent ? component.latestPageEvent.pageIndex : null).toBe(0);
expect(component.pageEvent).toHaveBeenCalledWith(jasmine.objectContaining({
previousPageIndex: 3,
pageIndex: 0
}));
});

it('should disable navigating to the next page if at last page', () => {
Expand All @@ -183,21 +195,21 @@ describe('MatPaginator', () => {
expect(paginator.pageIndex).toBe(9);
expect(paginator.hasNextPage()).toBe(false);

component.latestPageEvent = null;
component.pageEvent.calls.reset();
dispatchMouseEvent(getNextButton(fixture), 'click');

expect(component.latestPageEvent).toBe(null);
expect(component.pageEvent).not.toHaveBeenCalled();
expect(paginator.pageIndex).toBe(9);
});

it('should disable navigating to the previous page if at first page', () => {
expect(paginator.pageIndex).toBe(0);
expect(paginator.hasPreviousPage()).toBe(false);

component.latestPageEvent = null;
component.pageEvent.calls.reset();
dispatchMouseEvent(getPreviousButton(fixture), 'click');

expect(component.latestPageEvent).toBe(null);
expect(component.pageEvent).not.toHaveBeenCalled();
expect(paginator.pageIndex).toBe(0);
});

Expand Down Expand Up @@ -264,35 +276,37 @@ describe('MatPaginator', () => {
fixture.detectChanges();

// The first item of the page should be item with index 40
let firstPageItemIndex: number | null = paginator.pageIndex * paginator.pageSize;
expect(firstPageItemIndex).toBe(40);
expect(paginator.pageIndex * paginator.pageSize).toBe(40);

// The first item on the page is now 25. Change the page size to 25 so that we should now be
// on the second page where the top item is index 25.
component.pageEvent.calls.reset();
paginator._changePageSize(25);
let paginationEvent = component.latestPageEvent;
firstPageItemIndex = paginationEvent ?
paginationEvent.pageIndex * paginationEvent.pageSize : null;
expect(firstPageItemIndex).toBe(25);
expect(paginationEvent ? paginationEvent.pageIndex : null).toBe(1);

expect(component.pageEvent).toHaveBeenCalledWith(jasmine.objectContaining({
pageIndex: 1,
pageSize: 25
}));

// The first item on the page is still 25. Change the page size to 8 so that we should now be
// on the fourth page where the top item is index 24.
component.pageEvent.calls.reset();
paginator._changePageSize(8);
paginationEvent = component.latestPageEvent;
firstPageItemIndex = paginationEvent ?
paginationEvent.pageIndex * paginationEvent.pageSize : null;
expect(firstPageItemIndex).toBe(24);
expect(paginationEvent ? paginationEvent.pageIndex : null).toBe(3);

expect(component.pageEvent).toHaveBeenCalledWith(jasmine.objectContaining({
pageIndex: 3,
pageSize: 8
}));

// The first item on the page is 24. Change the page size to 16 so that we should now be
// on the first page where the top item is index 0.
component.pageEvent.calls.reset();
paginator._changePageSize(25);
paginationEvent = component.latestPageEvent;
firstPageItemIndex = paginationEvent ?
paginationEvent.pageIndex * paginationEvent.pageSize : null;
expect(firstPageItemIndex).toBe(0);
expect(paginationEvent ? paginationEvent.pageIndex : null).toBe(0);

expect(component.pageEvent).toHaveBeenCalledWith(jasmine.objectContaining({
pageIndex: 0,
pageSize: 25
}));
});

it('should show a select only if there are multiple options', () => {
Expand Down Expand Up @@ -357,7 +371,7 @@ function getLastButton(fixture: ComponentFixture<any>) {
[hidePageSize]="hidePageSize"
[showFirstLastButtons]="showFirstLastButtons"
[length]="length"
(page)="latestPageEvent = $event">
(page)="pageEvent($event)">
</mat-paginator>
`,
})
Expand All @@ -368,8 +382,7 @@ class MatPaginatorApp {
hidePageSize = false;
showFirstLastButtons = false;
length = 100;

latestPageEvent: PageEvent | null;
pageEvent = jasmine.createSpy('page event');

@ViewChild(MatPaginator) paginator: MatPaginator;

Expand Down
34 changes: 25 additions & 9 deletions src/lib/paginator/paginator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export class PageEvent {
/** The current page index. */
pageIndex: number;

/**
* Index of the page that was selected previously.
* @deletion-target 7.0.0 To be made into a required property.
*/
previousPageIndex?: number;

/** The current page size */
pageSize: number;

Expand Down Expand Up @@ -136,31 +142,39 @@ export class MatPaginator implements OnInit, OnDestroy {
/** Advances to the next page if it exists. */
nextPage(): void {
if (!this.hasNextPage()) { return; }

const previousPageIndex = this.pageIndex;
this.pageIndex++;
this._emitPageEvent();
this._emitPageEvent(previousPageIndex);
}

/** Move back to the previous page if it exists. */
previousPage(): void {
if (!this.hasPreviousPage()) { return; }

const previousPageIndex = this.pageIndex;
this.pageIndex--;
this._emitPageEvent();
this._emitPageEvent(previousPageIndex);
}

/** Move to the first page if not already there. */
firstPage(): void {
// hasPreviousPage being false implies at the start
if (!this.hasPreviousPage()) { return; }

const previousPageIndex = this.pageIndex;
this.pageIndex = 0;
this._emitPageEvent();
this._emitPageEvent(previousPageIndex);
}

/** Move to the last page if not already there. */
lastPage(): void {
// hasNextPage being false implies at the end
if (!this.hasNextPage()) { return; }

const previousPageIndex = this.pageIndex;
this.pageIndex = this.getNumberOfPages();
this._emitPageEvent();
this._emitPageEvent(previousPageIndex);
}

/** Whether there is a previous page. */
Expand Down Expand Up @@ -192,10 +206,11 @@ export class MatPaginator implements OnInit, OnDestroy {
// Current page needs to be updated to reflect the new page size. Navigate to the page
// containing the previous page's first item.
const startIndex = this.pageIndex * this.pageSize;
this.pageIndex = Math.floor(startIndex / pageSize) || 0;
const previousPageIndex = this.pageIndex;

this.pageIndex = Math.floor(startIndex / pageSize) || 0;
this.pageSize = pageSize;
this._emitPageEvent();
this._emitPageEvent(previousPageIndex);
}

/**
Expand All @@ -213,19 +228,20 @@ export class MatPaginator implements OnInit, OnDestroy {
}

this._displayedPageSizeOptions = this.pageSizeOptions.slice();
if (this._displayedPageSizeOptions.indexOf(this.pageSize) == -1) {

if (this._displayedPageSizeOptions.indexOf(this.pageSize) === -1) {
this._displayedPageSizeOptions.push(this.pageSize);
}

// Sort the numbers using a number-specific sort function.
this._displayedPageSizeOptions.sort((a, b) => a - b);

this._changeDetectorRef.markForCheck();
}

/** Emits an event notifying that a change of the paginator's properties has been triggered. */
private _emitPageEvent() {
private _emitPageEvent(previousPageIndex: number) {
this.page.emit({
previousPageIndex,
pageIndex: this.pageIndex,
pageSize: this.pageSize,
length: this.length
Expand Down
4 changes: 2 additions & 2 deletions src/lib/table/table.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ describe('MatTable', () => {
component.sort.sort(component.sortHeader);
fixture.detectChanges();
expectTableToMatchContent(tableElement, [
['Column A\xa0Sorted by a ascending', 'Column B', 'Column C'],
['Column A', 'Column B', 'Column C'],
['-1', 'b_3', 'c_3'],
['0', 'b_2', 'c_2'],
['1', 'b_1', 'c_1'],
Expand All @@ -289,7 +289,7 @@ describe('MatTable', () => {
component.sort.sort(component.sortHeader);
fixture.detectChanges();
expectTableToMatchContent(tableElement, [
['Column A\xa0Sorted by a descending', 'Column B', 'Column C'],
['Column A', 'Column B', 'Column C'],
['1', 'b_1', 'c_1'],
['0', 'b_2', 'c_2'],
['-1', 'b_3', 'c_3'],
Expand Down