I love the work of ng-bootstrap's guys, but I think that, definetively is not a good example. In my opinion, to have all in a service is not clear.
I make something in this SO with material angular. In general you need an API with two functions
getLength(string filter)
//and
getData(page:number,pageSize:number,filter:string,sortField:string,sortDirection:string)
In this anohter stackbliz is made it using ng-bootstrap
The idea is similar, we defined some auxiliar variables
total: number;
filter = new FormControl();
page:number=1;
pageSize:number=5;
elements$:Observable<any>
pag:BehaviorSubject<any>=new BehaviorSubject<any>(null);
paginator$=this.pag.asObservable();
sort:any={active:"position",direction:'desc'};
isLoadingResults = true;
Anf in ngOnInit we subscribe to filter.valueChanges
const obsFilter=this.filter.valueChanges.pipe(
debounceTime(200),
startWith(null),
switchMap((res: string) => this.dataService.getLength(res)),
tap((res: number) => {
this.page=1;
this.total = res;
})
);
this.elements$=merge(obsFilter, this.paginator$)
.pipe(
distinctUntilChanged(),
switchMap(res => {
return this.dataService.getData(
this.page,
this.pageSize,
this.filter.value,
this.sort.active,
this.sort.direction
);
}),
tap(_ => (this.isLoadingResults = false))
)
We are going to use the auxiliar this.paginagtor$ that emit a value when the page or the pageSize change and when sort change, so our function sort becomes like
onSort({column, direction}: SortEvent) {
// resetting other headers
this.sort={active:column,direction:direction}
this.headers.forEach(header => {
if (header.sortable !== column) {
header.direction = '';
}
});
this.pag.next(this.sort)
}
And the .html (see how we split the [(ngModel)] in paginator)
<form>
<div class="form-group form-inline">
Full text search: <input class="form-control ml-2" type="text" name="searchTerm" [formControl]="filter"/>
<span class="ml-3" *ngIf="isLoadingResults">Loading...</span>
</div>
<table class="table table-striped">
<thead>
<tr>
<th scope="col" sortable="position" (sort)="onSort($event)">No.</th>
<th scope="col" sortable="name" (sort)="onSort($event)">Name</th>
<th scope="col" sortable="weight" (sort)="onSort($event)">Weight</th>
<th scope="col" sortable="symbol" (sort)="onSort($event)">Symbol</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let element of elements$ | async">
<th scope="row">{{ element.position }}</th>
<td>
<ngb-highlight [result]="element.name" [term]="filter.value"></ngb-highlight>
</td>
<td><ngb-highlight [result]="element.weight | number" [term]="filter.value"></ngb-highlight></td>
<td><ngb-highlight [result]="element.symbol" [term]="filter.value"></ngb-highlight></td>
</tr>
</tbody>
</table>
<div class="d-flex justify-content-between p-2">
<ngb-pagination
[collectionSize]="total" [page]="page" (pageChange)="page=$event;pag.next($event)" [pageSize]="pageSize">
</ngb-pagination>
<select class="custom-select" style="width: auto" name="pageSize" [ngModel]="pageSize" (ngModelChange)="pageSize=$event;pag.next(-pageSize)">
<option [ngValue]="5">5 items per page</option>
<option [ngValue]="10">10 items per page</option>
<option [ngValue]="20">20 items per page</option>
</select>
</div>
</form>