byCoder
byCoder

Reputation: 9184

RXjs: reset true value after period of time

I have such service/state:

export class SpinnerService {
  public throttleTime: number = 10;
  public isLoading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

  constructor() {}

  public showLoader(): void {
    this.isLoading$.next(true);
  }

  public hideLoader(): void {
    this.isLoading$.next(false);
  }

  public get isLoadingAPIVal$(): Observable<boolean> {
    return this.isLoading$.pipe(throttleTime(this.throttleTime), shareReplay());
  }
}

Basically - here I store & get if I need to show app loading animation. I can set this value in multiple components in the same time or with any delays. For example I set isLoading$ to true in one component, and after 0.004sec in another. And everything works fine. Except one case.

Sometimes I need to set isLoading$ to false after it's last true value was set > 20 seconds from now.

How can I reset it to false after it was set to true last time and after 20sec?

I tried so:

  constructor() {
    this.isLoading$
      .pipe(
        filter((val) => !!val),
        timeout(20000),
      )
      .subscribe(() => {
        this.isLoading$.next(false);
      });
  }

but looks that it's not working and it takes first true value.

Upvotes: 0

Views: 480

Answers (1)

ccjmne
ccjmne

Reputation: 9618

What you probably want to do is:

public get isLoadingAPIVal$(): Observable<boolean> {
  return merge(
    this.isLoading$,
    this.isLoading$.pipe(
      debounceTime(20000),
      map(() => false),
    ),
  ).pipe(
    throttleTime(this.throttleTime),
    shareReplay(),
  );
}

What it does is:

  1. debounce the signals from isLoading$, to get a new signal 20 seconds after isLoading$ last emitted anything:
    this.isLoading$.pipe(
      debounceTime(20000),
    
  2. emit false values then:
    map(() => false),
    
  3. merge your original stream of signals, and the final debounced "false" answer 20 seconds later together :)
    merge(
      this.isLoading$,
      this.isLoading$.pipe(
        debounceTime(20000),
        map(() => false),
      ),
    )
    

Upvotes: 1

Related Questions