2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 import {Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
20 import {merge, Observable, Subject} from "rxjs";
21 import {UserInfo} from "../../../model/user-info";
22 import {TranslateService} from "@ngx-translate/core";
23 import {debounceTime, distinctUntilChanged, map, mergeMap, pluck, share, startWith} from "rxjs/operators";
24 import {EntityService} from "../../../model/entity-service";
28 * This component has a search field and pagination section. Entering data in the search field, or
29 * a button click on the pagination triggers a call to a service method, that returns the entity data.
30 * The service must implement the {@link EntityService} interface.
32 * The content is displayed between the search input and the pagination section. To use the data, you should
33 * add an identifier and refer to the item$ variable:
35 * <app-paginated-entities #parent>
37 * <tr ngFor="let entity in parent.item$ | async" >
38 * <td>{{entity.id}}</td>
41 * </app-paginated-entities>
44 * @typeparam T The type of the retrieved entity elements.
47 selector: 'app-paginated-entities',
48 templateUrl: './paginated-entities.component.html',
49 styleUrls: ['./paginated-entities.component.scss']
51 export class PaginatedEntitiesComponent<T> implements OnInit {
54 * This must be set, if you use the component. This service retrieves the entity data.
56 @Input() service : EntityService<T>;
59 * The number of elements per page retrieved
61 @Input() pageSize = 10;
66 @Input() pagination = {
74 * The current page that is selected
78 * The current search term entered in the search field
83 * Event thrown, if the page value changes
85 @Output() pageEvent : EventEmitter<number> = new EventEmitter<number>();
87 * Event thrown, if the search term changes
89 @Output() searchTermEvent: EventEmitter<string> = new EventEmitter<string>();
92 * The total number of elements available for the given search term
94 total$: Observable<number>;
96 * The entity items retrieved from the service
98 items$: Observable<T[]>;
100 private pageStream: Subject<number> = new Subject<number>();
101 private searchTermStream: Subject<string> = new Subject<string>();
106 // We combine the sources for the page and the search input field to a observable 'source'
107 const pageSource = this.pageStream.pipe(map(pageNumber => {
108 return {search: this.searchTerm, page: pageNumber}
110 const searchSource = this.searchTermStream.pipe(
112 distinctUntilChanged(),
114 this.searchTerm = searchTerm;
115 return {search: searchTerm, page: 1}
117 const source = merge(pageSource, searchSource).pipe(
118 startWith({search: this.searchTerm, page: this.page}),
119 mergeMap((params: { search: string, page: number }) => {
120 return this.service(params.search, (params.page - 1) * this.pageSize, this.pageSize, "", "asc");
122 this.total$ = source.pipe(pluck('pagination','totalCount'));
123 this.items$ = source.pipe(pluck('data'));
126 search(terms: string) {
127 // console.log("Keystroke " + terms);
128 this.searchTermEvent.emit(terms);
129 this.searchTermStream.next(terms)
132 changePage(pageNumber : number) {
133 // console.log("Page change " +pageNumber);
134 this.pageEvent.emit(pageNumber);
135 this.pageStream.next(pageNumber);