I have an Angular 6 app with the following requirements:

  1. Get data from a web service.
  2. Load the data when the page is displayed.
  3. Reload the data when the user requests a reload by through some UI, like a button.
  4. Show a spinner while loading data in the header of the page. That is, not in the same place where the data is going to be displayed. Which means I cannot use ngIf with ; else #loading.

I have the following (simplified) code that is actually working. I also have a live code sample. However I wonder if this is the canonical way to do it. Especially as I a am new to RxJS. Other improvements or suggestions are also welcome.

Some things I am not sure of:

  • Using the refresh Subject to do load/reload.
  • Setting the loading member within RxJS operators (side effects).

The component:

  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
export class AppComponent  {
  refresh: Subject<string>; // For load/reload
  items$: Observable<any>; // Some items

  loading: boolean = true; // Turn spinner on and off

  constructor (private http: HttpClient) { }

  ngOnInit() {
    this.refresh = new Subject();

    this.items$ = this.refresh.asObservable()
        startWith('onInit'), // Emit value to force load on page load; actual value does not matter
        flatMap(_ => this.http.get<any>('https://swapi.co/api/people/')), // Get some items
        delay(1000), // Delay to let our spinner shine
        map(data => data.results), // Map data
        tap(_ => this.loading = false) // Turn off the spinner

  onRefresh() {
    this.loading = true; // Turn on the spinner.
    this.refresh.next('onRefresh'); // Emit value to force reload; actual value does not matter

The template:

<div class="header">
  <h1>Items <a href="#"><i class="fas fa-sync" (click)="onRefresh()"></i></a> <i class="fas fa-spinner fa-spin" *ngIf="loading"></i></h1>

<div class="content">
  <div *ngIf="items$ | async as items">
      <li *ngFor="let item of items">
  • \$\begingroup\$ In this context, it is better to use switchMap than flatMap. \$\endgroup\$ – rveerd Nov 6 '19 at 13:34
  • \$\begingroup\$ This breaks when an error occurs. The items$ observable completes (with an error) and calling refresh.next() no longer has any effect. \$\endgroup\$ – rveerd Nov 6 '19 at 13:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.