DEV Community

Discussion on: Angular HTTP Pending Request Pattern

Collapse
 
johncarroll profile image
John Carroll

Hmm. This seems like more boilerplate than is needed to determine if something is loading. The HttpClient is a great example, because a request is loading while the request observable is incomplete.

In the case of the HttpClient, I think a simpler solution is a service which simply monitors the HttpClient request and returns true or false depending on whether the request had completed or not. Then in the template, you could subscribe to that service to see if the request was loading.

For example, when loading a user you could say

const request = this.http.get<User>(`https://swapi.co/api/people/${userId}`);

isLoading.add(request, { key: "user-loading" })
Enter fullscreen mode Exit fullscreen mode

And then in the template you could have something like

<section *ngIf="request | async as user">
  <h3>{{user.name}}</h3>
  <p>Height: {{user.height}}</p>
  <p>Mass: {{user.mass}}</p>
  <p>Homeworld: {{user.homeworld}}</p>
</section>

<section *ngIf="isLoading.loading('user-loading') | async">
  <span>Loading User...</span>
</section>
Enter fullscreen mode Exit fullscreen mode

Of course, you could get fancier and introduce custom pipes or directives to help yourself out, but the general concept is simple

<section *ngIf="'user-loading' | isLoadingPipe | async">
  <span>Loading User...</span>
</section>
Enter fullscreen mode Exit fullscreen mode

Handling errors wouldn't be proscribed in any way. For example, someone could simply return a special request object with a success property and any relevant data.

Unsurprisingly, I wrote a post on this strategy.

It also adds more flexibility to the user, because sometimes "loading" can come from multiple sources. In my app for example, I have a form component that is dynamically, and lazily, built from multiple sources. The form itself doesn't have any particular knowledge of it's children and the children don't have knowledge of each other. How then, to tell the form when it has finished loading? Well in this case, each child can simply add loading indicators keyed to the form's ID.

For example:

ngOnInit() {
  const fetchFormChildData = this.getData();

  this.isLoading.add(fetchFormChildData, {
    key: this.formId,
  })
}
Enter fullscreen mode Exit fullscreen mode

Here, isLoading.loading(this.formId) will resolve to true so long as any children are loading. Anyway, you can see more in the post.

Collapse
 
coryrylan profile image
Cory Rylan • Edited

I like your custom pipe strategy! Very nice post.

I ran into this pattern mostly because of the error handling. I could handle errors at the service level and then use a toast UI pattern or some kind of global level UI to display error but this app needed errors inline in multiple places within the UI. Because of this I was trying to find a way to reduce the amount of logic within the templates/components for error/retry messages.

In the app that I tried this on I had a generic service that abstracted away the boiler plate code you mentioned which helps some. I'm planing on writing up a small follow up post or add on to this that shows an example of making it more generic.

Collapse
 
johncarroll profile image
John Carroll

I see the advantage to normalizing http error handling as you've described, but I'm still skeptical that this approach to loading is generally applicable. It doesn't strike me as generally helpful to link the loading status to the error status (though it certainly might be in specific contexts), but I'll look for your follow up post 👍.

There are many times when I want to indicate something is "loading", without creating a specific error handler for that thing. For example, if I was lazy loading a component, I might want to indicate that something was loading while relying on a global error handler to trigger if the client happened to have lost their internet connection.