Simple Angular "isLoading?" Service Library
Tags: typescript, angular, showdev, githunt
Published: 2018-09-30 11:08:55

---
title: Simple Angular "isLoading?" Service Library
published: true
description: A simple and flexible loading indicator service for Angular apps.
tags: Typescript, Angular, showdev, githunt
---

[IsLoadingService](https://gitlab.com/service-work/is-loading) is a simple angular service for tracking whether your app, or parts of it, are loading. By subscribing to its `isLoading$()` method, you can easily know when to display loading indicators.

At its most basic, you can import the service into your root component and use `ngIf` + the `AsyncPipe` to show a loading indicator during page navigation.

Example:

```typescript
import { IsLoadingService } from '@service-work/is-loading';

@Component({
  selector: 'app-root',
  template: `
    <mat-progress-bar
      *ngIf="isLoading | async"
      mode="indeterminate"
      color="warn"
      style="position: absolute; top: 0; z-index: 100;"
    >
    </mat-progress-bar>

    <router-outlet></router-outlet>
  `,
})
export class AppComponent {
  isLoading: Observable<boolean>;

  constructor(
    private isLoadingService: IsLoadingService,
    private router: Router,
  ) {}

  ngOnInit() {
    this.isLoading = this.isLoadingService.isLoading$();

    this.router.events
      .pipe(
        filter(
          event =>
            event instanceof NavigationStart ||
            event instanceof NavigationEnd ||
            event instanceof NavigationCancel ||
            event instanceof NavigationError,
        ),
      )
      .subscribe(event => {
        // if it's the start of navigation, `add()` a loading indicator
        if (event instanceof NavigationStart) {
          this.isLoadingService.add();
          return;
        }

        // else navigation has ended, so `remove()` a loading indicator
        this.isLoadingService.remove();
      });
  }
}
```

If you want to manually indicate that something is loading, you can call the `loadingService.add()` method, and then call the `loadingService.remove()` method when loading has stopped.

If you call `loadingService.add()` multiple times (because multiple things are loading), `isLoading$()` will remain true until you call `remove()` an equal number of times.

Internally, the IsLoadingService maintains an array of loading indicators. Whenever you call `add()` it pushes an indicator onto the stack, and `remove()` removes an indicator from the stack. `isLoading$()` is true so long as there are any loading indicators on the stack.

You can also pass a subscription or promise argument to `loadingService.add(subscription)`. In this case, the loading service will push a loading indicator onto the stack, and then automatically remove it when the subscription closes / promise resolves (i.e. you don't need to manually call `remove()`.

### Advanced Usage

For more advanced scenarios, you can call `add()` with an options object containing a `key` property. The key allows you to track the loading of different things seperately. Any truthy value can be used as a key. The key option for `add()` is intended to be used in conjunction with `key` option for `isLoading$()` and `remove()`.

Example:

```typescript
class MyCustomComponent implements OnInit, AfterViewInit {
  constructor(
    private loadingService: IsLoadingService,
    private myCustomDataService: MyCustomDataService,
  ) {}

  ngOnInit() {
    this.loadingService.add({key: MyCustomComponent})

    const subscription = this.myCustomDataService.getData().subscribe()

    // Note, we don't need to call remove() when calling
    // add() with a subscription
    this.loadingService.add(subscription, {
      key: 'getting-data'
    })
  }

  ngAfterViewInit() {
    this.loadingService.remove({key: MyCustomComponent})
  }

  isDataLoading(): boolean {
    // the `isLoading()` method (without the `$`) returns a boolean
    // instead of an observable
    return this.loadingService.isLoading({key: 'getting-data'})
  }
}

```

### Wrapping Up

This service is very simple, but I've found myself often recreating it in different applications so I decided to package it up and publish it. It also helps get around a few Angular quirks I've run into, by debouncing and deduplicating `isLoading$` emissions which can otherwise mess up Angular's change detection.

Personally, I hook it up to a global loading indicator in my app's root component and let it automatically respond to router navigation. Additionally, when loading data from an API, I generally want to display that same app loading indicator, so I'll simply add the data fetch subscriptions with `loadingService.add(subOne)` + `loadingService.add(subTwo)`. Though if I wanted to display a different loading indicator for data fetching, I could use the optional `key` argument when calling `add()` and `isLoading$()`.


## [You can check it out on GitLab](https://gitlab.com/service-work/is-loading)