DEV Community

Rens Jaspers
Rens Jaspers

Posted on • Updated on

Production-Ready Asynchronous Data Loading: Implementing Pull-to-Refresh in Angular + Ionic 7 with Ion Refresher and NgxLoadWith

In the previous post, we learned about the IonRefresher component and how to integrate a pull-to-refresh functionality into an Angular and Ionic 7 application. We addressed how data loading, error handling, loading indication, HTTP request cancellation, and performance optimization are crucial for delivering a seamless user experience.

Now, let's take a step further and see how we can handle these aspects with significantly less code by using the NgxLoadWith directive. This post will guide you through integrating the NgxLoadWith directive with the Ionic's ion-refresher component, simplifying the process and allowing you to create a performant, user-friendly mobile application.

What is NgxLoadWith?

The NgxLoadWith directive is a useful tool for Angular applications that brings simplicity and effectiveness to asynchronous data loading. It handles error catching, loading indication, HTTP request cancellation, and works wonderfully with ChangeDetectionStrategy.OnPush. With NgxLoadWith, you won't need to worry about those complex data loading procedures anymore. Let's get started with the integration process.

Set Up

Let's pick up from where we left off last time. We have a page to display our todos, and we've just added the refreshing feature using the Ion Refresher component. Now, we'll start integrating the NgxLoadWith directive.

First, make sure you have installed the ngx-load-with module. You can do it by running the following command:

npm install ngx-load-with
Enter fullscreen mode Exit fullscreen mode

How to Use NgxLoadWith?

Now, let's look at our code:

import { CommonModule } from "@angular/common";
import { HttpClient } from "@angular/common/http";
import { ChangeDetectionStrategy, Component, inject } from "@angular/core";
import { IonicModule } from "@ionic/angular";
import { NgxLoadWithModule } from "ngx-load-with";

interface Todo {
  title: string;
  completed: boolean;
}

@Component({
  selector: "app-todos",
  templateUrl: "./todos.page.html",
  styleUrls: ["./todos.page.scss"],
  standalone: true,
  imports: [IonicModule, CommonModule, NgxLoadWithModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TodosPage {
  todos$ = inject(HttpClient).get<Todo[]>("https://jsonplaceholder.typicode.com/todos");
}
Enter fullscreen mode Exit fullscreen mode

In our revised TodosPage, we've now integrated the NgxLoadWith directive. The NgxLoadWithModule is consequently imported into our component.

Our todos$ Observable is handed to the NgxLoadWith directive, which takes over from here, managing everything from data loading to error handling. We're enhancing performance too, by adopting ChangeDetectionStrategy.OnPush. It's worth noting the change in our interaction with the Observable: we're no longer subscribing to it directly within our component. That's also handled by NgxLoadWith.

Let's see how this integrates with our HTML:

<ion-header>
  <ion-toolbar>
    <ion-title>Pull Down to Refresh</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <ion-refresher #refresher slot="fixed" (ionRefresh)="todosLoader.load()">
    <ion-refresher-content></ion-refresher-content>
  </ion-refresher>

  <ng-template
    #todosLoader="ngxLoadWith"
    [ngxLoadWith]="todos$"
    [ngxLoadWithLoadingTemplate]="loading"
    [ngxLoadWithErrorTemplate]="error"
    [ngxLoadWithStaleData]="true"
    (loadFinish)="refresher.complete()"
    let-todos
  >
    <ion-item *ngFor="let todo of todos">
      <ion-checkbox [checked]="todo.completed"> {{todo.title}}</ion-checkbox>
    </ion-item>
  </ng-template>
  <ng-template #loading>
    <ion-item *ngFor="let i of [1, 2, 3]">
      <ion-label>
        <ion-skeleton-text animated></ion-skeleton-text>
      </ion-label>
    </ion-item>
  </ng-template>
  <ng-template #error let-error>
    <ion-card>
      <ion-card-content>
        <p>Oops! Something went wrong. {{ error.message }}</p>
        <p>Pull down to try again!</p>
      </ion-card-content>
    </ion-card>
  </ng-template>
</ion-content>
Enter fullscreen mode Exit fullscreen mode

Within the ng-template tags, we create an instance of the NgxLoadWith directive, which we reference as todosLoader. This instance is essentially a helper that knows how to load data (using our getTodos method), show the correct template while loading, and handle potential errors.

As we pull to refresh, the IonRefresher emits the ionRefresh event. This event is connected to our todosLoader.load() method. This is where the magic happens: our todosLoader (an instance of NgxLoadWith) fires off the HTTP request, shows the loading template, and handles any errors by showing the error template.

What about when the data loading is finished, either with a successful response or an error? That's when the loadFinish event comes into play. Emitted by our NgxLoadWith instance, this event triggers refresher.complete(), which tells the IonRefresher to hide the refreshing spinner.

The ngxLoadWithStaleData input is a particularly neat feature. If set to true, NgxLoadWith will display the last successful response while a new load is in progress. This provides a smoother experience for the user, as they continue to see data even while fresh data is being loaded in the background.

So, with this setup, our IonRefresher and NgxLoadWith are tightly connected and reference each other, creating a seamless integration between refreshing and data loading. As a result, the user gets a slick pull-to-refresh experience with loading and error handling all taken care of.

Working example on StackBlitz

Conclusion

That's it! Now you know how to integrate NgxLoadWith with the Ionic ion-refresher component in Angular. The NgxLoadWith directive significantly simplifies asynchronous data loading, making your Angular applications more robust and easier to maintain. We've addressed error handling, loading indication, HTTP request cancellation, and performance optimization in one swoop, enhancing our user-friendly mobile application.

Stay tuned for more posts on using Angular and Ionic to build performant, feature-rich applications. As always, happy coding!

Top comments (0)