Skip to content

Commit

Permalink
feat(entity-table): add pagination (#707)
Browse files Browse the repository at this point in the history
* feat(entity-table) Pagination

* lint

* wip

* chore(build): build warn ng-packagr No name was provided for external module

* wip

* refactor(entity-table-paginator) refector individual input as options

* Update workspace.component.ts

* wip

* Update entity-table-paginator.component.html

* Update entity-table-paginator.component.ts

* fix(context-service) refer to issue #702 - message stored in base.json

* refactor(entity-table) translation and paginationOptions processing

* fix(entity-table)  deprecation warnint on event

* fix(entity-table) wrong last record used when clicking on a row (outside checkbox)

Co-authored-by: Marc-André Barbeau <[email protected]>
  • Loading branch information
2 people authored and Marc-André Barbeau committed Sep 8, 2020
1 parent 8f4f372 commit afde233
Show file tree
Hide file tree
Showing 23 changed files with 357 additions and 28 deletions.
5 changes: 4 additions & 1 deletion demo/src/app/common/entity-table/entity-table.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
</mat-card-content>
<igo-entity-table
[store]="store"
[template]="template">
[withPaginator]="true"
[paginatorOptions]="paginatorOptions"
[template]="template"
(entitySortChange)="entitySortChange()">
</igo-entity-table>
</mat-card>
28 changes: 22 additions & 6 deletions demo/src/app/common/entity-table/entity-table.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import {
EntityStore,
EntityTableButton,
getEntityProperty,
EntityTableColumnRenderer
EntityTableColumnRenderer,
EntityTablePaginatorOptions
} from '@igo2/common';
import { MatPaginator } from '@angular/material/paginator';
import { BehaviorSubject } from 'rxjs';

@Component({
selector: 'app-entity-table',
Expand All @@ -15,6 +18,10 @@ import {
})
export class AppEntityTableComponent implements OnInit, OnDestroy {
public store = new EntityStore([]);
public paginator: MatPaginator;
entitySortChange$: BehaviorSubject<boolean> = new BehaviorSubject(false);

public paginatorOptions: EntityTablePaginatorOptions = {pageSize: 10};

public template = {
selection: true,
Expand Down Expand Up @@ -66,11 +73,20 @@ export class AppEntityTableComponent implements OnInit, OnDestroy {
constructor(private languageService: LanguageService) {}

ngOnInit() {
this.store.load([
{ id: '2', name: 'Name 2', description: '<b>Description 2</b>' },
{ id: '1', name: 'Name 1', description: '<b>Description 1</b>' },
{ id: '3', name: 'Name 3', description: '<b>Description 3</b>' }
]);
const ids = [2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];

const entities = ids.map(id => {
return { id , name: `Name ${id}`, description: `<b>Description ${id}</b>`};
});
this.store.load(entities);
}

entitySortChange() {
this.entitySortChange$.next(true);
}

paginatorChange(event: MatPaginator) {
this.paginator = event;
}

ngOnDestroy() {
Expand Down
5 changes: 3 additions & 2 deletions demo/src/app/common/entity-table/entity-table.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NgModule } from '@angular/core';
import { MatCardModule } from '@angular/material/card';

import { IgoEntityTableModule } from '@igo2/common';
import { IgoEntityTableModule, IgoEntityTablePaginatorModule } from '@igo2/common';

import { AppEntityTableComponent } from './entity-table.component';
import { AppEntityTableRoutingModule } from './entity-table-routing.module';
Expand All @@ -11,7 +11,8 @@ import { AppEntityTableRoutingModule } from './entity-table-routing.module';
imports: [
AppEntityTableRoutingModule,
MatCardModule,
IgoEntityTableModule
IgoEntityTableModule,
IgoEntityTablePaginatorModule
],
exports: [AppEntityTableComponent]
})
Expand Down
2 changes: 1 addition & 1 deletion demo/src/app/geo/legend/legend.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export class AppLegendComponent {
visible: true,
legendOptions: {
display: false,
html: "test html"
html: 'test html'
},
sourceOptions: {
type: 'wms',
Expand Down
17 changes: 14 additions & 3 deletions demo/src/app/geo/workspace/workspace.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,36 @@
[store]="workspaceStore"
[map]="map">
</igo-workspace-selector>

<igo-entity-table-paginator
*ngIf="selectedWorkspace$ | async as workspace"
[store]="workspace.entityStore"
[paginatorOptions]="paginatorOptions"
[entitySortChange$]="entitySortChange$"
(paginatorChange)="paginatorChange($event)">
</igo-entity-table-paginator>

<ng-container *ngIf="selectedWorkspace$ | async as workspace">
<igo-actionbar
*ngIf="workspace.actionStore"
[store]="workspace.actionStore"
[horizontal]="true"
[withToggleButton]="true"
[withTitle]="false"
[withTitle]="true"
[mode]="actionbarMode">
</igo-actionbar>

<igo-workspace-widget-outlet [workspace]="workspace"></igo-workspace-widget-outlet>

<igo-entity-table
*ngIf="workspace.entityStore && workspace.meta && workspace.meta.tableTemplate"
class="table-compact table-centered"
[paginator]="workspacePaginator"
[scrollBehavior]="scrollBehavior"
[store]="workspace.entityStore"
[template]="workspace.meta.tableTemplate">
</igo-entity-table>

<igo-workspace-widget-outlet [workspace]="workspace"></igo-workspace-widget-outlet>

</ng-container>

</mat-card>
40 changes: 35 additions & 5 deletions demo/src/app/geo/workspace/workspace.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, OnInit } from '@angular/core';

import { Observable } from 'rxjs';
import { Observable, BehaviorSubject } from 'rxjs';
import { map } from 'rxjs/operators';

import { LanguageService } from '@igo2/core';
Expand All @@ -9,22 +9,35 @@ import {
EntityRecord,
EntityTableScrollBehavior,
Workspace,
WorkspaceStore
WorkspaceStore,
EntityTablePaginatorOptions
} from '@igo2/common';
import {
IgoMap,
DataSourceService,
LayerService,
WFSDataSourceOptions
} from '@igo2/geo';
import { OgcFilterableDataSourceOptions } from 'packages/geo/src/public_api';
import { MatPaginator } from '@angular/material/paginator';

@Component({
selector: 'app-workspace',
templateUrl: './workspace.component.html',
styleUrls: ['./workspace.component.scss']
})
export class AppWorkspaceComponent implements OnInit {

public workspacePaginator: MatPaginator;
entitySortChange$: BehaviorSubject<boolean> = new BehaviorSubject(false);
public paginatorOptions: EntityTablePaginatorOptions = {
disabled: false, // Whether the component is disabled.
pageIndex: 3, // The zero-based page index of the displayed list of items.
hidePageSize: false, // Whether to hide the page size selection UI from the user.
pageSize: 5, // Number of items to display on a page.
pageSizeOptions: [1, 5, 10, 15, 30, 50, 100], // The set of provided page size options to display to the user.
showFirstLastButtons: true // Whether to show the first/last buttons UI to the user.
};

public map = new IgoMap({
controls: {
attribution: {
Expand All @@ -42,7 +55,7 @@ export class AppWorkspaceComponent implements OnInit {

public selectedWorkspace$: Observable<Workspace>;

public actionbarMode = ActionbarMode.Dock;
public actionbarMode = ActionbarMode.Overlay;

public scrollBehavior = EntityTableScrollBehavior.Instant;

Expand All @@ -59,7 +72,20 @@ export class AppWorkspaceComponent implements OnInit {
)
.pipe(
map((record: EntityRecord<Workspace>) => {
return record === undefined ? undefined : record.entity;
const entity = record === undefined ? undefined : record.entity;
if (entity) {
// In fact, the download action is not fully functionnal into the igo2-lib demo
// The reason why it's has been remove is that this button trigger a tool (importExport)
// and this tool is not available in the igo2-lib demo.
// This is why it's has been removed frome the actions's list.
// Refer to the igo2 demo at https://infra-geo-ouverte.github.io/igo2/
entity.actionStore.view.filter((action) => {
console.log('action', action);
return action.id !== 'wfsDownload';
});
}
return entity;

})
);

Expand Down Expand Up @@ -143,4 +169,8 @@ export class AppWorkspaceComponent implements OnInit {
this.map.addLayer(this.layerService.createLayer(layer));
});
}

paginatorChange(event: MatPaginator) {
this.workspacePaginator = event;
}
}
3 changes: 2 additions & 1 deletion packages/common/ng-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"@igo2/utils" : "utils",
"scroll-into-view-if-needed" : "scrollIntoView",
"typy" : "typy",
"@ngx-translate/core" : "ngxt-core"
"@ngx-translate/core" : "ngxt-core",
"angular-shepherd": "angularShepherd"
}
}
}
3 changes: 2 additions & 1 deletion packages/common/ng-package.prod.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"@igo2/utils" : "utils",
"scroll-into-view-if-needed" : "scrollIntoView",
"typy" : "typy",
"@ngx-translate/core" : "ngxt-core"
"@ngx-translate/core" : "ngxt-core",
"angular-shepherd": "angularShepherd"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<mat-paginator
[disabled]="disabled"
[hidePageSize]="hidePageSize"
[length]="length"
[pageIndex]="pageIndex"
[pageSize]="pageSize"
[pageSizeOptions]="pageSizeOptions"
[showFirstLastButtons]="showFirstLastButtons"
(page)="emitPaginator()">
</mat-paginator>
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import {
Component,
Input,
ChangeDetectionStrategy,
OnInit,
ViewChild,
Output,
EventEmitter,
OnDestroy
} from '@angular/core';

import {
EntityStore
} from '../shared';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { BehaviorSubject, Subscription } from 'rxjs';
import { LanguageService } from '@igo2/core';
import { EntityTablePaginatorOptions } from './entity-table-paginator.interface';

@Component({
selector: 'igo-entity-table-paginator',
templateUrl: './entity-table-paginator.component.html',
styleUrls: ['./entity-table-paginator.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EntityTablePaginatorComponent implements OnInit, OnDestroy {

public disabled: boolean = false;
public hidePageSize: boolean = false;
public pageIndex: number = 0;
public pageSize: number = 50;
public pageSizeOptions: number[] = [5, 10, 20, 50, 100, 200];
public showFirstLastButtons: boolean = true;
private entitySortChange$$: Subscription;
private paginationLabelTranslation$$: Subscription[] = [];

@Input() entitySortChange$: BehaviorSubject<boolean> = new BehaviorSubject(false);
/**
* Entity store
*/
@Input() store: EntityStore<object>;

/**
* Paginator options
*/
@Input()
paginatorOptions: EntityTablePaginatorOptions;

/**
* Event emitted when the paginator changes the page size or page index.
*/
@Output() page: EventEmitter<PageEvent>;

public length: number = 0;

/**
* Paginator emitted.
*/
@Output() paginatorChange: EventEmitter<MatPaginator> = new EventEmitter<MatPaginator>();

constructor(private languageService: LanguageService) { }

@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;

ngOnInit() {
this.store.stateView.count$.subscribe((count) => {
this.length = count;
this.emitPaginator();
});
this.entitySortChange$$ = this.entitySortChange$.subscribe(() => {
if (this.paginator) {
this.paginator.firstPage();
}
});
this.initPaginatorOptions();
this.translateLabels();
}

initPaginatorOptions() {
this.disabled = this.paginatorOptions?.disabled || this.disabled;
this.hidePageSize = this.paginatorOptions?.hidePageSize || this.hidePageSize;
this.pageIndex = this.paginatorOptions?.pageIndex || this.pageIndex;
this.pageSize = this.paginatorOptions?.pageSize || this.pageSize;
this.pageSizeOptions = this.paginatorOptions?.pageSizeOptions || this.pageSizeOptions;
this.showFirstLastButtons = this.paginatorOptions?.showFirstLastButtons || this.showFirstLastButtons;
}

translateLabels() {

this.paginationLabelTranslation$$.push(
this.languageService.translate.get('igo.common.paginator.firstPageLabel').subscribe((label: string) => {
this.paginator._intl.firstPageLabel = label;
}));

this.paginator._intl.getRangeLabel = this.rangeLabel;

this.paginationLabelTranslation$$.push(
this.languageService.translate.get('igo.common.paginator.itemsPerPageLabel').subscribe((label: string) => {
this.paginator._intl.itemsPerPageLabel = label;
}));
this.paginationLabelTranslation$$.push(
this.languageService.translate.get('igo.common.paginator.lastPageLabel').subscribe((label: string) => {
this.paginator._intl.lastPageLabel = label;
}));
this.paginationLabelTranslation$$.push(
this.languageService.translate.get('igo.common.paginator.nextPageLabel').subscribe((label: string) => {
this.paginator._intl.nextPageLabel = label;
}));
this.paginationLabelTranslation$$.push(
this.languageService.translate.get('igo.common.paginator.previousPageLabel').subscribe((label: string) => {
this.paginator._intl.previousPageLabel = label;
}));
}

rangeLabel = (page: number, pageSize: number, length: number) => {
const of: BehaviorSubject<string> = new BehaviorSubject('');

this.paginationLabelTranslation$$.push(
this.languageService.translate.get('igo.common.paginator.of').subscribe((label: string) => {
of.next(label);
}));
if (length === 0 || pageSize === 0) { return `0 ${of.value} ${length}`; }
length = Math.max(length, 0);
const startIndex = page * pageSize;
const endIndex = startIndex < length ?
Math.min(startIndex + pageSize, length) :
startIndex + pageSize;
return `${startIndex + 1} - ${endIndex} ${of.value} ${length}`;
}

ngOnDestroy(): void {
this.entitySortChange$$.unsubscribe();
this.paginationLabelTranslation$$.map(sub => sub.unsubscribe());
}

emitPaginator() {
this.paginatorChange.emit(this.paginator);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface EntityTablePaginatorOptions {
disabled?: boolean; // Whether the component is disabled.
hidePageSize?: boolean; // Whether to hide the page size selection UI from the user.
pageIndex?: number; // The zero-based page index of the displayed list of items.
pageSize?: number; // Number of items to display on a page.
pageSizeOptions?: number[]; // The set of provided page size options to display to the user.
showFirstLastButtons?: boolean; // Whether to show the first/last buttons UI to the user.
}
Loading

0 comments on commit afde233

Please sign in to comment.