I'm attempting to use ngx-pagination
to implement server side pagination on my Angular 6 application.
I've followed the documentation to best of my ability but I've encountered the following problems and don't know how to proceed.
Problems
The component loads and gets the data from the api but is not displayed on render until after I would've made two more calls to the api by navigating to the next page and then to previous.
Data on page two of the api is not being called.
Screenshots
After back and forth navigation
Sample Code
import { Component, OnInit, Input, ChangeDetectionStrategy } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ApiService } from '../../services/api.service';
import { SiteUrls } from '../../services/constants.service';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs';
import { map, tap } from 'rxjs/operators';
import 'rxjs/add/operator/delay';
interface IServerResponse {
items: any[];
total: number;
}
@Component({
selector: 'app-sample',
templateUrl: './sample.component.html',
styleUrls: ['./sample.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SampleComponent implements OnInit {
@Input() sample: any = [{}];
total: number;
p = 1;
pagedItems: Observable<any[]>;
public meta: any = {};
constructor(private site: SiteUrls, private http: Http, private api: ApiService) {}
ngOnInit() {
this.getPage(1);
}
async getPage(page: number) {
this.pagedItems = this.serverCall(this.sample, page)
.pipe(tap((res) => {
this.total = res.total;
this.p = page;
console.log('total', this.total, 'page', this.p, 'res', res);
})).pipe(map((res) => res.items));
}
serverCall(sample: any[], page: number): Observable<IServerResponse> {
this.getsample();
const perPage = this.meta.per_page;
const start = (page - 1) * perPage;
const end = start + perPage;
return of({
items: sample.slice(start, end),
total: this.meta.total
}).delay(1000);
}
private getsample() {
this.api.get('sample').subscribe((data) => {
this.sample = data.body.data;
this.meta = data.body.meta;
});
}
}
<tbody>
<tr *ngFor="let tran of pagedItems | async | paginate: { itemsPerPage: meta.per_page, currentPage: p, totalItems: meta.total }">
<td>
{{tran.account.number}}
</td>
<td>
{{tran.sender.name}}
</td>
<td>
{{tran.recipient.name}}
</td>
<td>
{{tran.date | date: 'MMMM dd, yyyy'}}
</td>
<td style="background-color: antiquewhite">
{{tran.subtotal | currency}}
</td>
<td style="background-color: antiquewhite">
{{tran.fee | currency}}
</td>
<td style="background-color: antiquewhite">
<b>{{tran.total | currency}}</b>
</td>
</tr>
</tbody>
</table>
<pagination-controls (pageChange)="getPage($event)"></pagination-controls>
Any help would be appreciated.
UPDATE
getsample()
is being executed on page load and api returns the data.
For safety, I've changed the method an async
one so it now looks like this:
async getsample() {
try {
await this.api.get('sample').subscribe((data) => {
this.sample = data.body.data;
this.meta = data.body.meta;
});
} catch (error) {}
}
I also implemented the answer given by Brandon but the problem still persist.
There are more problems with your code, one of them is your call to this.getsample();
that is asynchronous, but you do not wait for the result.
Another thing is that you cannot await observable. Convert it to promise first via .toPromise()
instead of subscribing, or do not use promises at all and subscribe instead (but only at the very top level - in ngOnInit
handler).
Using async/await:
async ngOnInit() {
await this.getsample(); // move the loading here
await this.getPage(1);
}
async getPage(page: number) {
const res = await this.serverCall(this.sample, page);
this.total = res.total;
this.p = page;
console.log('total', this.total, 'page', this.p, 'res', res);
this.pagedItems = res.items;
}
async serverCall(sample: any[], page: number): Promise<IServerResponse> {
const perPage = this.meta.per_page;
const start = (page - 1) * perPage;
const end = start + perPage;
return of({
items: sample.slice(start, end),
total: this.meta.total
}).delay(1000).toPromise(); // convert the observable to promise
}
private async getsample() {
const data = await this.api.get('sample').toPromise(); // and again here
this.sample = data.body.data;
this.meta = data.body.meta;
}