Paginate API data

Hi there,

I have data returned by API and I need to paginate the results by infinite scroll, getting all data at once is a source killer for me and also takes long time.

Logic

  1. Page shows loading and gets first 10 data of API result (currently have loading but it gets all data)
  2. infinite scroll (each time add 10 more data till last one)

Code

Provider

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { LoadingController } from '@ionic/angular';

@Injectable({
  providedIn: 'root'
})
export class CategoriesService {

  apiUrl = 'https://example.com/api/categories';

  constructor(private http: HttpClient, private loadingCtrl: LoadingController) { }

  getDetails(url) {
    const httpOptions = {
      headers: new HttpHeaders({
        'Accept': 'application/json, text/plain',
        'Content-Type': 'application/json'
      })
    };

    return this.http.get(`${this.apiUrl}/${url}`, httpOptions).pipe(
      map(category => category)
    );
  }
}

Module

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { CategoriesService } from './../../services/categories.service';
import { LoadingController } from '@ionic/angular';

@Component({
  selector: 'app-categories-details',
  templateUrl: './categories-details.page.html',
  styleUrls: ['./categories-details.page.scss'],
})
export class CategoriesDetailsPage implements OnInit {

  categories: Observable<any>;
  loading: any;

  constructor(
    private categoriesService: CategoriesService,
    public loadingController: LoadingController,
  ) {}

  ngOnInit() {
    this.getData();
  }

  async getData(){
    this.loading = await this.loadingController.create({
      message: 'Please wait...',
      spinner: 'crescent',
      duration: 2000
    });

    await this.loading.present();

    this.categoriesService.getCategories().subscribe((res) => {
      this.categories = res;
      this.hideLoading()
    });
  }

  private hideLoading() {
    this.loading.dismiss();
  }
}

View

<ion-content padding>
    <ion-grid>
        <ion-row>
          <ion-list *ngIf="category">
            <ion-item *ngFor="let post of category.posts">
              <ion-avatar slot="start">
                 <img [routerLink]="['/', 'posts', post.url]" [src]="post.image">
              </ion-avatar>
                <ion-label class="ion-text-wrap" [routerLink]="['/', 'posts', post.url]">{{post.title}}</ion-label>
            </ion-item>
          </ion-list>
        </ion-row>
      </ion-grid>
</ion-content>

Based on docs I added this to my view below my loop code

<ion-infinite-scroll threshold="150px" (ionInfinite)="loadMorePosts($event)">
    <ion-infinite-scroll-content
      loadingSpinner="bubbles"
      loadingText="Loading more data...">
    </ion-infinite-scroll-content>
</ion-infinite-scroll>

And this to my Module

//....
import { LoadingController, IonInfiniteScroll } from '@ionic/angular';

//...
@ViewChild(IonInfiniteScroll) infiniteScroll: IonInfiniteScroll;
//....

Now please if someone can tell me how to handle loadMorePosts($event) function for my code I’ll be appreciate it.

Thank you.

Well I managed to get my posts by pagination and show infinite loading, 1 issue remained and that’s about disabling infinite scroll after all posts are loaded.

My latest code is like:

  posts: any[] =[];
  totalPosts = 0;
  limit = 10;
  loading: any;

  @ViewChild(IonInfiniteScroll) infiniteScroll: IonInfiniteScroll;

  constructor(private postsService: PostsService, public loadingController: LoadingController) {}

  ngOnInit() {
    this.getData();
  }

  async getData() {
    this.loading = await this.loadingController.create({
      message: 'Please wait...',
      spinner: 'crescent',
      duration: 2000
    });

    await this.loading.present();

    this.postsService.getPosts().subscribe((res) => {
      this.totalPosts = res.length;
      for (let post of res) {
        this.posts.push(post);
      }
      this.hideLoading();
    });
  }

  private hideLoading() {
    this.loading.dismiss();
  }

  //have issue here about "disabling"
  loadMorePosts(event) {
    setTimeout(() => {
      console.log('Begin async operation');
      this.limit += 10;
      event.target.complete();

      if (this.posts.length == this.limit) {
        event.target.disabled = true;
      }
    }, 500);
  }
  //

  toggleInfiniteScroll() {
    this.infiniteScroll.disabled = !this.infiniteScroll.disabled;
  }

Digging

In my code placed this.totalPosts = res.length; and at the top I have totalPosts = 0;, I made this in order to use it in if (this.posts.length == this.totalPosts ) { to disable scroll when it already gets all posts but it returned error so for temporary I changed it to if (this.posts.length == this.limit) { just to avoid errors.

Question

How do I disable scroll when all posts are loaded?

UPDATE

I manage to solve disabling issue with this code

if (this.posts.length < this.limit) {
  event.target.disabled = true;
}

I changed this.posts.length == this.limit with this.posts.length < this.limit

Now working just fine :smiley:

Hope it help others.

3 Likes

Yes, this solution work for me.
i wish we can do same with horizontal infiniteScroll soon