How to show a loading spinner while waiting on an observable getting data from a service in Angular

Thank you all for your responses, but none of these suggestions worked for the purposes outlined in the question, but I did work on a solution and eventually got one working. Here we go:

In the service I created a new Observable called loading$ and set it up as a new BehaviorSubject<boolean>(true);

Then I created a getter:

getLoading(): Observable<boolean> {
return this.loading$;
}

Then I wrapped the HTTP call with a true then set loading to false in the 3rd argument on the subscription (the onCompleted function).

So the service looks like this:

import { Observable, BehaviorSubject, of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class OrganisationsService {
  private organisations$ = new BehaviorSubject<Organisation[]>([
    {
      [...]
    }
  ]);

  //initiate the new Loading variable via BehaviorSubject and set it to "true" from the beginning.
  public loading$ = new BehaviorSubject<boolean>(true);

  constructor(private http: HttpClient) {

    //set the loading$ to true again just before we start the HTTP call
    this.loading$.next(true);


    this.http
      .get(environment.apicall)
      .subscribe(

        //onNext method, where we get the data
        (data) => this.organisations$.next(data['organisations']),

        //onError method (Blank for now)
        () => {},

        //onComplated method, now that we have the data we can set the loading to false
        () => {
          this.loading$.next(false);
        }
      );
  }

  getLoading(): Observable<boolean> {
    return this.loading$;
  }

  getList(): Observable<Organisation[]> {
    return this.organisations$;
  }

Notice in the subscribe method on the HTTP call, I’m adding a blank second method (This is for onError) and then in the 3rd method, I’ve added a function to set the loading to false: this.loading$.next(false); . This means that Loading will now be false when the subscription is complete.

Then in my component, I get the loading$ subscription:

      public loading$: Observable<boolean>;
      public organisations$: Observable<Organisation[]>;

      constructor(public organisationsService: OrganisationsService) {}

      ngOnInit() {
        this.getData();
      }

      async getData() {

        //initially loading$ will be true because the service makes it so
        this.loading$ = this.organisationsService.getLoading();

        //when this completes, loading$ will be set to false via the service
        this.organisations$ = this.organisationsService.getList();
      }

And in my view:

  <div>
    <div uk-spinner *ngIf="loading$ | async"></div>
    <ul class="uk-list">
      <li *ngFor="let organisation of organisations$ | async">
        {{ organisation.name }}
      </li>
    </ul>
  </div>

Leave a Comment