Production-Ready Asynchronous Data Loading: Implementing Pull-to-Refresh in Angular + Ionic 7 with Ion Refresher and NgxLoadWith
Tags: beginners, angular, ionic, ngxloadwith
Published: 2023-06-01 16:48:00

In the [previous post](https://dev.to/rensjaspers/implementing-pull-to-refresh-with-ionic-7-angular-and-the-ion-refresher-component-4cjp), 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](https://npmjs.com/ngx-load-with). 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:

```bash
npm install ngx-load-with
```

## How to Use NgxLoadWith?

Now, let's look at our code:

```typescript
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");
}
```

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:

```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>
```

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](https://stackblitz.com/edit/angular-xt44ud-81tyyc?file=src%2Fapp%2Fapp.component.html)

## Conclusion

That's it! Now you know how to integrate [`NgxLoadWith`](https://npmjs.com/ngx-load-with) 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!