mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
#70 pagination support for document list
This commit is contained in:
@@ -27,7 +27,8 @@ import {
|
|||||||
OnChanges,
|
OnChanges,
|
||||||
TemplateRef,
|
TemplateRef,
|
||||||
NgZone,
|
NgZone,
|
||||||
ViewChild
|
ViewChild,
|
||||||
|
HostListener
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Subject } from 'rxjs/Rx';
|
import { Subject } from 'rxjs/Rx';
|
||||||
import { CONTEXT_MENU_DIRECTIVES } from 'ng2-alfresco-core';
|
import { CONTEXT_MENU_DIRECTIVES } from 'ng2-alfresco-core';
|
||||||
@@ -53,15 +54,13 @@ declare let __moduleName: string;
|
|||||||
styleUrls: ['./document-list.css'],
|
styleUrls: ['./document-list.css'],
|
||||||
templateUrl: './document-list.html',
|
templateUrl: './document-list.html',
|
||||||
providers: [DocumentListService],
|
providers: [DocumentListService],
|
||||||
directives: [CONTEXT_MENU_DIRECTIVES, ALFRESCO_DATATABLE_DIRECTIVES],
|
directives: [CONTEXT_MENU_DIRECTIVES, ALFRESCO_DATATABLE_DIRECTIVES]
|
||||||
host: {
|
|
||||||
'(contextmenu)': 'onShowContextMenu($event)'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, AfterContentInit, OnChanges {
|
export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, AfterContentInit, OnChanges {
|
||||||
|
|
||||||
static SINGLE_CLICK_NAVIGATION: string = 'click';
|
static SINGLE_CLICK_NAVIGATION: string = 'click';
|
||||||
static DOUBLE_CLICK_NAVIGATION: string = 'dblclick';
|
static DOUBLE_CLICK_NAVIGATION: string = 'dblclick';
|
||||||
|
static DEFAULT_PAGE_SIZE: number = 20;
|
||||||
|
|
||||||
DEFAULT_ROOT_FOLDER: string = '/';
|
DEFAULT_ROOT_FOLDER: string = '/';
|
||||||
|
|
||||||
@@ -85,6 +84,9 @@ export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, Af
|
|||||||
@Input()
|
@Input()
|
||||||
contextMenuActions: boolean = false;
|
contextMenuActions: boolean = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
pageSize: number = DocumentList.DEFAULT_PAGE_SIZE;
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
nodeClick: EventEmitter<any> = new EventEmitter();
|
nodeClick: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
@@ -154,6 +156,7 @@ export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, Af
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.data.thumbnails = this.thumbnails;
|
this.data.thumbnails = this.thumbnails;
|
||||||
|
this.data.maxItems = this.pageSize;
|
||||||
this.displayFolderContent(this.currentFolderPath);
|
this.displayFolderContent(this.currentFolderPath);
|
||||||
this.contextActionHandler.subscribe(val => this.contextActionCallback(val));
|
this.contextActionHandler.subscribe(val => this.contextActionCallback(val));
|
||||||
}
|
}
|
||||||
@@ -211,6 +214,7 @@ export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, Af
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HostListener('contextmenu', ['$event'])
|
||||||
onShowContextMenu(e?: Event) {
|
onShowContextMenu(e?: Event) {
|
||||||
if (e) {
|
if (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -365,5 +369,4 @@ export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, Af
|
|||||||
this.executeContentAction(node, action);
|
this.executeContentAction(node, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -13,11 +13,15 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</span>
|
</span>
|
||||||
<span class="mdl-paging__count">1-10 of 25</span>
|
<span class="mdl-paging__count">{{summary}}</span>
|
||||||
<button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon mdl-paging__prev">
|
<button (click)="showPrevPage()"
|
||||||
|
[disabled]="!prevPageAvail"
|
||||||
|
alfresco-mdl-button class="mdl-button--icon mdl-paging__prev">
|
||||||
<i class="material-icons">keyboard_arrow_left</i>
|
<i class="material-icons">keyboard_arrow_left</i>
|
||||||
</button>
|
</button>
|
||||||
<button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon mdl-paging__next">
|
<button (click)="showNextPage()"
|
||||||
|
[disabled]="!nextPageAvail"
|
||||||
|
alfresco-mdl-button class="mdl-button--icon mdl-paging__next">
|
||||||
<i class="material-icons">keyboard_arrow_right</i>
|
<i class="material-icons">keyboard_arrow_right</i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
MATERIAL_DESIGN_DIRECTIVES,
|
MATERIAL_DESIGN_DIRECTIVES,
|
||||||
PaginationProvider
|
PaginationProvider
|
||||||
@@ -30,7 +30,9 @@ declare let __moduleName: string;
|
|||||||
styleUrls: ['./pagination.component.css'],
|
styleUrls: ['./pagination.component.css'],
|
||||||
directives: [MATERIAL_DESIGN_DIRECTIVES]
|
directives: [MATERIAL_DESIGN_DIRECTIVES]
|
||||||
})
|
})
|
||||||
export class DocumentListPagination implements OnInit {
|
export class DocumentListPagination {
|
||||||
|
|
||||||
|
DEFAULT_PAGE_SIZE: number = 20;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
supportedPageSizes: number[] = [5, 10, 20, 50, 100];
|
supportedPageSizes: number[] = [5, 10, 20, 50, 100];
|
||||||
@@ -38,17 +40,47 @@ export class DocumentListPagination implements OnInit {
|
|||||||
@Input()
|
@Input()
|
||||||
provider: PaginationProvider;
|
provider: PaginationProvider;
|
||||||
|
|
||||||
@Input()
|
get pageSize(): number {
|
||||||
pageSize: number = 10;
|
if (this.provider) {
|
||||||
|
return this.provider.maxItems;
|
||||||
|
}
|
||||||
|
return this.DEFAULT_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {}
|
set pageSize(value: number) {
|
||||||
|
if (this.provider) {
|
||||||
|
this.provider.maxItems = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setPageSize(value: number) {
|
setPageSize(value: number) {
|
||||||
this.pageSize = value;
|
this.pageSize = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
get summary(): string {
|
||||||
console.info(this.provider);
|
let from = this.provider.skipCount;
|
||||||
|
if (from === 0) {
|
||||||
|
from = 1;
|
||||||
|
}
|
||||||
|
let to = this.provider.skipCount + this.provider.count;
|
||||||
|
let of = this.provider.totalItems;
|
||||||
|
return `${from}-${to} of ${of}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get nextPageAvail(): boolean {
|
||||||
|
return this.provider.hasMoreItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
get prevPageAvail(): boolean {
|
||||||
|
return this.provider.skipCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
showNextPage() {
|
||||||
|
this.provider.skipCount += this.provider.maxItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
showPrevPage() {
|
||||||
|
this.provider.skipCount -= this.provider.maxItems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -94,13 +94,13 @@ describe('ShareDataTableAdapter', () => {
|
|||||||
it('should fail when getting value for missing row', () => {
|
it('should fail when getting value for missing row', () => {
|
||||||
let adapter = new ShareDataTableAdapter(null, null, null);
|
let adapter = new ShareDataTableAdapter(null, null, null);
|
||||||
let check = () => { return adapter.getValue(null, <DataColumn>{}); };
|
let check = () => { return adapter.getValue(null, <DataColumn>{}); };
|
||||||
expect(check).toThrowError(ShareDataTableAdapter.ERR_ROW_NOT_FOUND);
|
expect(check).toThrowError(adapter.ERR_ROW_NOT_FOUND);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail when getting value for missing column', () => {
|
it('should fail when getting value for missing column', () => {
|
||||||
let adapter = new ShareDataTableAdapter(null, null, null);
|
let adapter = new ShareDataTableAdapter(null, null, null);
|
||||||
let check = () => { return adapter.getValue(<DataRow>{}, null); };
|
let check = () => { return adapter.getValue(<DataRow>{}, null); };
|
||||||
expect(check).toThrowError(ShareDataTableAdapter.ERR_COL_NOT_FOUND);
|
expect(check).toThrowError(adapter.ERR_COL_NOT_FOUND);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should require path to load data', () => {
|
it('should require path to load data', () => {
|
||||||
@@ -283,7 +283,7 @@ describe('ShareDataTableAdapter', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should resolve file thumbnail', () => {
|
it('should resolve file thumbnail', () => {
|
||||||
let imageUrl: 'http://<addresss>';
|
let imageUrl: string = 'http://<addresss>';
|
||||||
spyOn(documentListService, 'getDocumentThumbnailUrl').and.returnValue(imageUrl);
|
spyOn(documentListService, 'getDocumentThumbnailUrl').and.returnValue(imageUrl);
|
||||||
|
|
||||||
let adapter = new ShareDataTableAdapter(documentListService, basePath, null);
|
let adapter = new ShareDataTableAdapter(documentListService, basePath, null);
|
||||||
|
@@ -27,22 +27,24 @@ import { DocumentListService } from './../services/document-list.service';
|
|||||||
|
|
||||||
export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvider {
|
export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvider {
|
||||||
|
|
||||||
static ERR_ROW_NOT_FOUND: string = 'Row not found';
|
ERR_ROW_NOT_FOUND: string = 'Row not found';
|
||||||
static ERR_COL_NOT_FOUND: string = 'Column not found';
|
ERR_COL_NOT_FOUND: string = 'Column not found';
|
||||||
|
|
||||||
static DEFAULT_DATE_FORMAT: string = 'medium';
|
DEFAULT_DATE_FORMAT: string = 'medium';
|
||||||
static DEFAULT_PAGE_SIZE: number = 100;
|
DEFAULT_PAGE_SIZE: number = 20;
|
||||||
|
MIN_PAGE_SIZE: number = 5;
|
||||||
|
|
||||||
private sorting: DataSorting;
|
private sorting: DataSorting;
|
||||||
private rows: DataRow[];
|
private rows: DataRow[];
|
||||||
private columns: DataColumn[];
|
private columns: DataColumn[];
|
||||||
private page: NodePaging;
|
private page: NodePaging;
|
||||||
|
private currentPath: string;
|
||||||
|
|
||||||
private _count: number = 0;
|
private _count: number = 0;
|
||||||
private _hasMoreItems: boolean = false;
|
private _hasMoreItems: boolean = false;
|
||||||
private _totalItems: number = 0;
|
private _totalItems: number = 0;
|
||||||
private _skipCount: number = 0;
|
private _skipCount: number = 0;
|
||||||
private _maxItems: number = ShareDataTableAdapter.DEFAULT_PAGE_SIZE;
|
private _maxItems: number = this.DEFAULT_PAGE_SIZE;
|
||||||
|
|
||||||
thumbnails: boolean = false;
|
thumbnails: boolean = false;
|
||||||
|
|
||||||
@@ -70,10 +72,24 @@ export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvid
|
|||||||
return this._skipCount;
|
return this._skipCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set skipCount(value: number) {
|
||||||
|
if (value !== this._skipCount) {
|
||||||
|
this._skipCount = value > 0 ? value : 0;
|
||||||
|
this.loadPath(this.currentPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get maxItems(): number {
|
get maxItems(): number {
|
||||||
return this._maxItems;
|
return this._maxItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set maxItems(value: number) {
|
||||||
|
if (value !== this._maxItems) {
|
||||||
|
this._maxItems = value > this.MIN_PAGE_SIZE ? value : this.MIN_PAGE_SIZE;
|
||||||
|
this.loadPath(this.currentPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getRows(): Array<DataRow> {
|
getRows(): Array<DataRow> {
|
||||||
return this.rows;
|
return this.rows;
|
||||||
}
|
}
|
||||||
@@ -94,16 +110,16 @@ export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvid
|
|||||||
|
|
||||||
getValue(row: DataRow, col: DataColumn): any {
|
getValue(row: DataRow, col: DataColumn): any {
|
||||||
if (!row) {
|
if (!row) {
|
||||||
throw new Error(ShareDataTableAdapter.ERR_ROW_NOT_FOUND);
|
throw new Error(this.ERR_ROW_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (!col) {
|
if (!col) {
|
||||||
throw new Error(ShareDataTableAdapter.ERR_COL_NOT_FOUND);
|
throw new Error(this.ERR_COL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
let value = row.getValue(col.key);
|
let value = row.getValue(col.key);
|
||||||
|
|
||||||
if (col.type === 'date') {
|
if (col.type === 'date') {
|
||||||
let datePipe = new DatePipe();
|
let datePipe = new DatePipe();
|
||||||
let format = col.format || ShareDataTableAdapter.DEFAULT_DATE_FORMAT;
|
let format = col.format || this.DEFAULT_DATE_FORMAT;
|
||||||
try {
|
try {
|
||||||
return datePipe.transform(value, format);
|
return datePipe.transform(value, format);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -193,8 +209,12 @@ export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvid
|
|||||||
|
|
||||||
loadPath(path: string) {
|
loadPath(path: string) {
|
||||||
if (path && this.documentListService) {
|
if (path && this.documentListService) {
|
||||||
|
this.currentPath = path;
|
||||||
this.documentListService
|
this.documentListService
|
||||||
.getFolder(path)
|
.getFolder(path, {
|
||||||
|
maxItems: this._maxItems,
|
||||||
|
skipCount: this._skipCount
|
||||||
|
})
|
||||||
.subscribe(val => this.loadPage(<NodePaging>val),
|
.subscribe(val => this.loadPage(<NodePaging>val),
|
||||||
error => console.error(error));
|
error => console.error(error));
|
||||||
}
|
}
|
||||||
@@ -240,7 +260,7 @@ export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvid
|
|||||||
this._hasMoreItems = false;
|
this._hasMoreItems = false;
|
||||||
this._totalItems = 0;
|
this._totalItems = 0;
|
||||||
this._skipCount = 0;
|
this._skipCount = 0;
|
||||||
this._maxItems = ShareDataTableAdapter.DEFAULT_PAGE_SIZE;
|
this._maxItems = this.DEFAULT_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -72,15 +72,25 @@ export class DocumentListService {
|
|||||||
return AlfrescoApi.getClientWithTicket(this.settings.getApiBaseUrl(), this.authService.getToken());
|
return AlfrescoApi.getClientWithTicket(this.settings.getApiBaseUrl(), this.authService.getToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
private getNodesPromise(folder: string) {
|
private getNodesPromise(folder: string, opts?: any) {
|
||||||
let alfrescoClient = this.getAlfrescoClient();
|
let alfrescoClient = this.getAlfrescoClient();
|
||||||
let apiInstance = new AlfrescoApi.Core.NodesApi(alfrescoClient);
|
let apiInstance = new AlfrescoApi.Core.NodesApi(alfrescoClient);
|
||||||
let nodeId = '-root-';
|
let nodeId = '-root-';
|
||||||
let opts = {
|
let params: any = {
|
||||||
relativePath: folder,
|
relativePath: folder,
|
||||||
include: ['path']
|
include: ['path']
|
||||||
};
|
};
|
||||||
return apiInstance.getNodeChildren(nodeId, opts);
|
|
||||||
|
if (opts) {
|
||||||
|
if (opts.maxItems) {
|
||||||
|
params.maxItems = opts.maxItems;
|
||||||
|
}
|
||||||
|
if (opts.skipCount) {
|
||||||
|
params.skipCount = opts.skipCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiInstance.getNodeChildren(nodeId, params);
|
||||||
}
|
}
|
||||||
deleteNode(nodeId: string) {
|
deleteNode(nodeId: string) {
|
||||||
let client = this.getAlfrescoClient();
|
let client = this.getAlfrescoClient();
|
||||||
@@ -93,10 +103,11 @@ export class DocumentListService {
|
|||||||
/**
|
/**
|
||||||
* Gets the folder node with the content.
|
* Gets the folder node with the content.
|
||||||
* @param folder Path to folder.
|
* @param folder Path to folder.
|
||||||
|
* @param opts Options
|
||||||
* @returns {Observable<NodePaging>} Folder entity.
|
* @returns {Observable<NodePaging>} Folder entity.
|
||||||
*/
|
*/
|
||||||
getFolder(folder: string): Observable<NodePaging> {
|
getFolder(folder: string, opts?: any): Observable<NodePaging> {
|
||||||
return Observable.fromPromise(this.getNodesPromise(folder))
|
return Observable.fromPromise(this.getNodesPromise(folder, opts))
|
||||||
.map(res => <NodePaging> res)
|
.map(res => <NodePaging> res)
|
||||||
// .do(data => console.log('Node data', data)) // eyeball results in the console
|
// .do(data => console.log('Node data', data)) // eyeball results in the console
|
||||||
.catch(this.handleError);
|
.catch(this.handleError);
|
||||||
|
Reference in New Issue
Block a user