Search code examples
rxjsrxjs6rxjs-pipeable-operators

rxjs: show loading spinner only if it takes > 1s to load


I have a Subject refreshData$ that triggers data refetch:

const data$ = refreshData$.pipe(
    switchMap(() => dataService.load())
);

I need to show loading indicator only if load take more than 1 second. If data arrives in under 1s - do not show the spinner.

Found very good answer here, but it recreates the observables on every refresh. And I want to reuse them. I have started with the following, but it it only works one time. I guess takeUntil has to be replaced with something else here.

const showSpinner$ = merge(
    refreshData$.pipe(
        delay(1000),
        mapTo(true),
        takeUntil(data$)    // FIXME: only shows loading once
    ),
    data$.pipe(
        timeInterval(),
        mapTo(false)
    )
);

----
to be used in template as:
<loading-spinner *ngIf="showSpinner|async"></loading-spinner>

Solution

  • I would create a disposable stream, so that if takeUntil() terminates it early, your outer observable (showSpinner$) continues.

    const showSpinner$ = merge(
      refreshData$.pipe(
        switchMap(_ => timer(1000).pipe(
          mapTo(true),
          takeUntil(data$)
        ))
      ),
      data$.pipe(
        mapTo(false)
      )
    );