We will add some more advanced behaviours
Code on github https://github.com/kendarorg/Angular101
Let's start adding a new method to the service to handle the DataSource. The data source is nice because it handles all the pagination, ordering, filtering and sorting. For our example we will handle only the pagination, that was implemented via http headers on the server.
First we need to import globally the paginator on app.module.ts
import { MatPaginatorModule } from '@angular/material/paginator';
And load it in the imports
imports: [
...
MatPaginatorModule,
],
We need to import the HttpHeaders and rxjs. The latter is needed to map the result from the request to a consistent object
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map } from 'rxjs/operators';
We add a new type to return, containing the data for the pagination (this could be placed in a common part since its "type agnostic"
export interface AddressResult {
body: Object;
pageCount: number;
totalCount: number;
pageIndex:number;
}
We will not use sorting and filter. Just the pagination. We are reading the data from the API that tells us the specification of the data, like the total count and the page index returned
public findAddresses(
addressId:number = -1, filter = '', sortOrder = 'asc',
pageNumber = 0, pageSize = 3):Observable<AddressResult> {
var headers = new HttpHeaders();
var address = this.baseUrl;
if(addressId>=0){
address+="/"+addressId;
}else{
headers = headers.set('X-Page',pageNumber.toString());
headers = headers.set('X-PageSize',pageSize.toString());
}
return this.http.get(address, {headers:headers, observe: "response"}).pipe(
map(res => {
var pageCount =parseInt(res.headers.get('X-PageCount'));
var pageIndex =parseInt(res.headers.get('X-PageIndex'));
var totalCount =parseInt(res.headers.get('X-Count'));
return {
body:res.body as AddressElement[],
pageCount:pageCount,
totalCount:totalCount,
pageIndex:pageIndex} as AddressResult;
})
);
}
We need to import
MatTableDataSource: The data source that we will use to show the results
import { AddressesDataService, AddressElement, AddressResult } from '../addresses-data.service'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { MatTable, MatTableDataSource } from '@angular/material/table';
We setup a new variable for the paginator. The annotation tells angular to initialize the item only when everything is ready
@ViewChild(MatPaginator, { static: false })
paginator: MatPaginator;
Then setup the data source and all the paginator variables
dataSource = new MatTableDataSource();
length: number;
pageIndex: number =0;
pageSize: number=3;
pageSizeOptions = [1, 5, 10, 50];
And an event. That will be monitored and will update the paginator
pageEvent: PageEvent;
Let's rewrite the getAddresses. It receives an event from paginator. If nothing is passed an empty object casted as an event is created filling the blanks with the default values.
Then a subscription to findAddresses is created that updates the values shown.
Finally the event is returned. Prettu straightforward for now. Notice the cast to Array of AddressElement of the AddressResult
getAddresses(event?:PageEvent){
if(event==null){
event ={pageIndex:0,pageSize:this.pageSize} as PageEvent;
}
this.dataService.findAddresses(-1,'','asc',event.pageIndex,event.pageSize).subscribe(
addresses =>{
var a = addresses as AddressResult;
this.addresses=a.body as Array<AddressElement>;
this.dataSource.data = this.addresses;
this.length=a.totalCount;
this.pageIndex = a.pageIndex;
},
error => {
console.log("error retrieving addresses");
}
);
return event;
}
The onInit will be greatly simplified. Just call getAddresses
ngOnInit(): void {
this.getAddresses(null);
}
dataSource: AddressesDs;
constructor(public dataService: AddressesDataService) {}
ngOnInit(): void {
this.dataSource = new AddressesDs(this.dataService);
this.dataSource.loadAddresses(-1);
}
The dataSource will be changed to dataSource
<mat-table [dataSource]="dataSource" class="mat-elevation-z1" >
We will add after the mat-table the following. #paginator tells Angular that a variable exists inside the controller with that value. The most interesting thing is the (page). This means that when the page is changed on the paginator an event is intercepted and sent to the controller!
<mat-paginator #paginator
[length]="length"
[pageSize]="pageSize"
[pageIndex]="pageIndex"
[pageSizeOptions]="pageSizeOptions"
(page)="pageEvent = getAddresses($event)">
</mat-paginator>
The controller will then call the service to get the data and it will be shown :D