Using OData paginated payload with ngx-bootstrap Pagination component
I have recently started playing around with OData, and it really easy to get things up and running with an existing database. All my frontend code is in Angular and I use ngx-bootstrap for all bootstrap components.
All the OData endpoints have stranded responses, I don’t want to change it. Now I need to do my Angular implementation to support OData stranded.
export interface IODataResponse<T> { '@odata.context': string; '@odata.nextLink': string; '@odata.count': number; value: T; }
my service class method looks like this
export class BaseService { constructor(private http: HttpClient) {} getPaged<T>(path: string, page: number, itemsPerPage: number, columns:string[], expand?:string[], filterParams?: HttpParams): Observable<T> { let params = new HttpParams() .set('$select', columns.toString()) .set('$count', true) .set('$top', itemsPerPage) .set('$skip', page > 1 ? (page -1) * itemsPerPage : 0); if(expand != null) params = params.append('$expand', expand.toString()); if(filterParams != null) params = this.mergeParams(params, filterParams); return this.http .get<T>(`${environment.api_url}${path}`, { params }) .pipe(catchError(this.formatErrors)); } private mergeParams(params: HttpParams, _params: HttpParams): HttpParams{ const items: any = _params; Object.keys(items.updates).forEach(function (key) { params = params.append(items.updates[key].param, items.updates[key].value); }); return params; } }
I can use the service class method to get data like below
getPaged<T>(page: number, itemsPerPage: number, columns:string[], searchTerm?: string): Observable<IODataResponse<T[]>> { const filterParams = new HttpParams() .set('$filter', `contains(salesOrderNumber,'${searchTerm}')`); const expand = ['customer($select=companyName,firstName,lastName)' + ',billToAddress($select=addressLine1,addressLine2,city,stateProvince,countryRegion,postalCode)' + ',shipToAddress($select=addressLine1,addressLine2,city,stateProvince,countryRegion,postalCode)']; return this.service.getPaged<IODataResponse<T[]>>(this.resource, page, itemsPerPage, columns, expand, searchTerm ? filterParams : undefined) .pipe(first()) .subscribe( (response: IODataResponse<ISalesOrder[]>) => { this.orders = response.value; this.totalItems = ODataHelper.getTotalItems(response, this.itemsPerPage); this.busy = false; }, (error: any) => { this.busy = false; } ); }
in order to extract the count from JSON payload, had to write a helper method
export abstract class ODataHelper { public static getTotalItems(response: any, itemsPerPage: number): number{ return (Math.trunc(response['@odata.count'] / itemsPerPage) * itemsPerPage) } }
Looks easy? let me know if there is a better way to do it.