Fix pagination issues

This commit is contained in:
Giuseppe Digilio
2017-07-28 20:19:54 +02:00
parent 713d00f96d
commit aa6afea6e2
7 changed files with 142 additions and 62 deletions

View File

@@ -1,6 +1,6 @@
import { import {
ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, Component, DoCheck, OnChanges, OnDestroy,
OnInit OnInit, SimpleChanges
} from '@angular/core'; } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router'; import { ActivatedRoute, Params } from '@angular/router';
@@ -16,6 +16,8 @@ import { Item } from '../core/shared/item.model';
import { SortOptions, SortDirection } from '../core/cache/models/sort-options.model'; import { SortOptions, SortDirection } from '../core/cache/models/sort-options.model';
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
import { hasValue } from '../shared/empty.util'; import { hasValue } from '../shared/empty.util';
import { PageInfo } from '../core/shared/page-info.model';
import { isUndefined } from 'util';
@Component({ @Component({
selector: 'ds-collection-page', selector: 'ds-collection-page',
@@ -23,7 +25,7 @@ import { hasValue } from '../shared/empty.util';
templateUrl: './collection-page.component.html', templateUrl: './collection-page.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class CollectionPageComponent implements OnInit, OnDestroy { export class CollectionPageComponent implements OnChanges, OnInit, OnDestroy {
collectionData: RemoteData<Collection>; collectionData: RemoteData<Collection>;
itemData: RemoteData<Item[]>; itemData: RemoteData<Item[]>;
logoData: RemoteData<Bitstream>; logoData: RemoteData<Bitstream>;
@@ -31,6 +33,7 @@ export class CollectionPageComponent implements OnInit, OnDestroy {
sortConfig: SortOptions; sortConfig: SortOptions;
private subs: Subscription[] = []; private subs: Subscription[] = [];
private collectionId: string; private collectionId: string;
private pageInfoState: PageInfo;
constructor( constructor(
private collectionDataService: CollectionDataService, private collectionDataService: CollectionDataService,
@@ -41,6 +44,10 @@ export class CollectionPageComponent implements OnInit, OnDestroy {
} }
ngOnChanges(changes: SimpleChanges) {
console.log(changes);
}
ngOnInit(): void { ngOnInit(): void {
this.subs.push(this.route.params.map((params: Params) => params.id) this.subs.push(this.route.params.map((params: Params) => params.id)
.subscribe((id: string) => { .subscribe((id: string) => {
@@ -84,13 +91,20 @@ export class CollectionPageComponent implements OnInit, OnDestroy {
} }
updateResults() { updateResults() {
this.itemData = undefined; this.itemData = null;
this.ref.markForCheck();
this.itemData = this.itemDataService.findAll({ this.itemData = this.itemDataService.findAll({
scopeID: this.collectionId, scopeID: this.collectionId,
currentPage: this.config.currentPage, currentPage: this.config.currentPage,
elementsPerPage: this.config.pageSize, elementsPerPage: this.config.pageSize,
sort: this.sortConfig sort: this.sortConfig
}); });
// this.ref.detectChanges(); this.itemData.pageInfo.subscribe((pageInfo) => {
if (isUndefined(this.pageInfoState) || this.pageInfoState !== pageInfo) {
this.pageInfoState = pageInfo;
this.ref.detectChanges();
}
});
} }
} }

View File

@@ -36,7 +36,6 @@ export class ResponseCacheService {
get(key: string): Observable<ResponseCacheEntry> { get(key: string): Observable<ResponseCacheEntry> {
return this.store.select<ResponseCacheEntry>('core', 'cache', 'response', key) return this.store.select<ResponseCacheEntry>('core', 'cache', 'response', key)
.filter((entry) => this.isValid(entry)) .filter((entry) => this.isValid(entry))
.distinctUntilChanged()
} }
/** /**

View File

@@ -1,4 +1,5 @@
<ds-pagination [paginationOptions]="config" <ds-pagination [paginationOptions]="config"
[pageInfoState]="pageInfo"
[collectionSize]="(pageInfo | async)?.totalElements" [collectionSize]="(pageInfo | async)?.totalElements"
[sortOptions]="sortConfig" [sortOptions]="sortConfig"
[hideGear]="hideGear" [hideGear]="hideGear"

View File

@@ -5,7 +5,7 @@ import {
ViewEncapsulation, ViewEncapsulation,
ChangeDetectionStrategy, ChangeDetectionStrategy,
OnInit, OnInit,
Output Output, SimpleChanges, OnChanges, ChangeDetectorRef, DoCheck
} from '@angular/core'; } from '@angular/core';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
@@ -25,7 +25,7 @@ import { SortOptions, SortDirection } from '../../core/cache/models/sort-options
styleUrls: ['../../object-list/object-list.component.scss'], styleUrls: ['../../object-list/object-list.component.scss'],
templateUrl: '../../object-list/object-list.component.html' templateUrl: '../../object-list/object-list.component.html'
}) })
export class ObjectListComponent implements OnInit { export class ObjectListComponent implements OnChanges, OnInit {
@Input() objects: RemoteData<DSpaceObject[]>; @Input() objects: RemoteData<DSpaceObject[]>;
@Input() config: PaginationComponentOptions; @Input() config: PaginationComponentOptions;
@@ -59,10 +59,26 @@ export class ObjectListComponent implements OnInit {
@Output() sortFieldChange: EventEmitter<string> = new EventEmitter<string>(); @Output() sortFieldChange: EventEmitter<string> = new EventEmitter<string>();
data: any = {}; data: any = {};
ngOnChanges(changes: SimpleChanges) {
if (changes.objects && !changes.objects.isFirstChange()) {
this.pageInfo = this.objects.pageInfo;
}
}
ngOnInit(): void { ngOnInit(): void {
this.pageInfo = this.objects.pageInfo; this.pageInfo = this.objects.pageInfo;
} }
/**
* @param route
* Route is a singleton service provided by Angular.
* @param router
* Router is a singleton service provided by Angular.
*/
constructor(
private cdRef: ChangeDetectorRef) {
}
onPageChange(event) { onPageChange(event) {
this.pageChange.emit(event); this.pageChange.emit(event);
} }

View File

@@ -1,3 +1,4 @@
<div *ngIf="currentPageState == undefined || currentPageState == currentPage">
<div *ngIf="!hideGear" class="pagination-masked clearfix top"> <div *ngIf="!hideGear" class="pagination-masked clearfix top">
<div class="row"> <div class="row">
<div class="col pagination-info"> <div class="col pagination-info">
@@ -32,3 +33,4 @@
[rotate]="paginationOptions.rotate" [rotate]="paginationOptions.rotate"
[size]="(isXs)?'sm':paginationOptions.size"></ngb-pagination> [size]="(isXs)?'sm':paginationOptions.size"></ngb-pagination>
</div> </div>
</div>

View File

@@ -2,6 +2,7 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { import {
ChangeDetectorRef,
Component, Component,
CUSTOM_ELEMENTS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA,
DebugElement DebugElement
@@ -161,6 +162,7 @@ describe('Pagination component', () => {
{ provide: GLOBAL_CONFIG, useValue: ENV_CONFIG }, { provide: GLOBAL_CONFIG, useValue: ENV_CONFIG },
{ provide: Router, useValue: routerStub }, { provide: Router, useValue: routerStub },
{ provide: HostWindowService, useValue: hostWindowServiceStub }, { provide: HostWindowService, useValue: hostWindowServiceStub },
ChangeDetectorRef,
PaginationComponent PaginationComponent
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]

View File

@@ -1,12 +1,12 @@
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy, ChangeDetectorRef,
Component, Component,
EventEmitter, EventEmitter,
Input, Input,
OnChanges,
OnDestroy, OnDestroy,
OnInit, OnInit,
Output, Output, SimpleChanges,
ViewEncapsulation ViewEncapsulation
} from '@angular/core' } from '@angular/core'
@@ -22,6 +22,10 @@ import { HostWindowState } from '../host-window.reducer';
import { PaginationComponentOptions } from './pagination-component-options.model'; import { PaginationComponentOptions } from './pagination-component-options.model';
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { hasValue } from '../empty.util'; import { hasValue } from '../empty.util';
import { PageInfo } from '../../core/shared/page-info.model';
import { isUndefined } from 'util';
import { Store } from '@ngrx/store';
import { ObjectCacheState } from '../../core/cache/object-cache.reducer';
/** /**
* The default pagination controls component. * The default pagination controls component.
@@ -33,13 +37,18 @@ import { hasValue } from '../empty.util';
changeDetection: ChangeDetectionStrategy.Default, changeDetection: ChangeDetectionStrategy.Default,
encapsulation: ViewEncapsulation.Emulated encapsulation: ViewEncapsulation.Emulated
}) })
export class PaginationComponent implements OnDestroy, OnInit { export class PaginationComponent implements OnChanges, OnDestroy, OnInit {
/** /**
* Number of items in collection. * Number of items in collection.
*/ */
@Input() collectionSize: number; @Input() collectionSize: number;
/**
* Page state of a Remote paginated objects.
*/
@Input() pageInfoState: Observable<PageInfo> = undefined;
/** /**
* Configuration for the NgbPagination component. * Configuration for the NgbPagination component.
*/ */
@@ -87,7 +96,12 @@ export class PaginationComponent implements OnDestroy, OnInit {
/** /**
* Current page. * Current page.
*/ */
public currentPage = 1; public currentPage;
/**
* Current page in the state of a Remote paginated objects.
*/
public currentPageState: number = undefined;
/** /**
* Current URL query parameters * Current URL query parameters
@@ -113,12 +127,12 @@ export class PaginationComponent implements OnDestroy, OnInit {
/** /**
* Number of items per page. * Number of items per page.
*/ */
public pageSize = 10; public pageSize;
/** /**
* Declare SortDirection enumeration to use it in the template * Declare SortDirection enumeration to use it in the template
*/ */
public sortDirections = SortDirection public sortDirections = SortDirection;
/** /**
* A number array that represents options for a context pagination limit. * A number array that represents options for a context pagination limit.
@@ -154,6 +168,15 @@ export class PaginationComponent implements OnDestroy, OnInit {
total: null total: null
}; };
ngOnChanges(changes: SimpleChanges) {
if (changes.pageInfoState && !changes.pageInfoState.isFirstChange()) {
this.subs.push(this.pageInfoState.subscribe((pageInfo) => {
/* TODO: this is a temporary fix for the pagination start index (0 or 1) discrepancy between the rest and the frontend respectively */
this.currentPageState = pageInfo.currentPage + 1;
}));
}
}
/** /**
* Method provided by Angular. Invoked after the constructor. * Method provided by Angular. Invoked after the constructor.
*/ */
@@ -161,28 +184,39 @@ export class PaginationComponent implements OnDestroy, OnInit {
this.subs.push(this.hostWindowService.isXs() this.subs.push(this.hostWindowService.isXs()
.subscribe((status: boolean) => { .subscribe((status: boolean) => {
this.isXs = status; this.isXs = status;
this.cdRef.markForCheck();
})); }));
this.checkConfig(this.paginationOptions); this.checkConfig(this.paginationOptions);
if (this.pageInfoState) {
this.subs.push(this.pageInfoState.subscribe((pageInfo) => {
/* TODO: this is a temporary fix for the pagination start index (0 or 1) discrepancy between the rest and the frontend respectively */
this.currentPageState = pageInfo.currentPage + 1;
}));
}
this.id = this.paginationOptions.id || null; this.id = this.paginationOptions.id || null;
this.currentPage = this.paginationOptions.currentPage;
this.pageSize = this.paginationOptions.pageSize;
this.pageSizeOptions = this.paginationOptions.pageSizeOptions; this.pageSizeOptions = this.paginationOptions.pageSizeOptions;
this.sortDirection = this.sortOptions.direction;
this.sortField = this.sortOptions.field;
this.subs.push(this.route.queryParams this.subs.push(this.route.queryParams
.filter((queryParams) => hasValue(queryParams)) .filter((queryParams) => hasValue(queryParams))
.subscribe((queryParams) => { .subscribe((queryParams) => {
this.currentQueryParams = queryParams; this.currentQueryParams = queryParams;
// tslint:disable:triple-equals if (this.id === queryParams.pageId
if (this.id == queryParams.pageId && (this.paginationOptions.currentPage !== +queryParams.page
&& (this.paginationOptions.currentPage != queryParams.page || this.paginationOptions.pageSize !== +queryParams.pageSize
|| this.paginationOptions.pageSize != queryParams.pageSize || this.sortOptions.direction !== +queryParams.sortDirection
|| this.sortOptions.direction !== queryParams.sortDirection
|| this.sortOptions.field !== queryParams.sortField) || this.sortOptions.field !== queryParams.sortField)
) { ) {
this.validateParams(queryParams.page, queryParams.pageSize, queryParams.sortDirection, queryParams.sortField); this.validateParams(queryParams.page, queryParams.pageSize, queryParams.sortDirection, queryParams.sortField);
} else if (isUndefined(queryParams.pageId) && !isUndefined(this.currentPage)) {
// When moving back from a page with query params to page without them, initialize to the first page
this.doPageChange(1);
} else {
this.currentPage = this.paginationOptions.currentPage;
this.pageSize = this.paginationOptions.pageSize;
this.sortDirection = this.sortOptions.direction;
this.sortField = this.sortOptions.field;
} }
// tslint:enable:triple-equals
})); }));
this.setShowingDetail(); this.setShowingDetail();
} }
@@ -203,6 +237,7 @@ export class PaginationComponent implements OnDestroy, OnInit {
* Router is a singleton service provided by Angular. * Router is a singleton service provided by Angular.
*/ */
constructor( constructor(
private cdRef: ChangeDetectorRef,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
public hostWindowService: HostWindowService) { public hostWindowService: HostWindowService) {
@@ -317,19 +352,30 @@ export class PaginationComponent implements OnDestroy, OnInit {
sortDirection: sortDirection, sortDirection: sortDirection,
sortField: sortField sortField: sortField
} }
} });
);
} else { } else {
// (+) converts string to a number // (+) converts string to a number
if (this.currentPage !== +page) {
this.currentPage = +page; this.currentPage = +page;
this.pageSize = +pageSize;
this.sortDirection = +sortDirection;
this.sortField = sortField;
this.pageChange.emit(this.currentPage); this.pageChange.emit(this.currentPage);
}
if (this.pageSize !== +pageSize) {
this.pageSize = +pageSize;
this.pageSizeChange.emit(this.pageSize); this.pageSizeChange.emit(this.pageSize);
}
if (this.sortDirection !== +sortDirection) {
this.sortDirection = +sortDirection;
this.sortDirectionChange.emit(this.sortDirection); this.sortDirectionChange.emit(this.sortDirection);
}
if (this.sortField !== sortField) {
this.sortField = sortField;
this.sortFieldChange.emit(this.sortField); this.sortFieldChange.emit(this.sortField);
} }
this.cdRef.detectChanges();
}
} }
/** /**