Amar T
Amar T

Reputation: 357

How do i explicitly trigger interval in rxjs

autoRefreshGateways() {
 return interval(GATEWAY_REFRESH_INTERVAL)
   .pipe(
     startWith(0),
     takeUntil(this.stopAutoRefresh),
     exhaustMap(() => this.fetchAllData())
   ).subscribe(
     (gateways) => {
       this.gateways = gateways;
     },
     () => {
       this.notificationsService.error(this.translateService.instant('zerotrust.gateway.list.error'), '')
     }
   );
}

I have this autoRefresh function which calls the api every 5 sec. In some scenario i dont want to wait for 5 second. I want to call fetchAllData immediatly based on some action from the UI. I have written a different function for that which will call fetchAllData. However is there a better solution to this?

Upvotes: 1

Views: 646

Answers (3)

olivarra1
olivarra1

Reputation: 3409

I think merge is your friend here.

Try to break down the problem by thinking of what's the signal to trigger the update: In your case you have 2 sources: autoRefreshes and forceRefreshes. That's easy to represent:

const forceRefresh = new Subject(); // In your case, you'd have this defined as an instance property of your class, so it can be called from outside.
const autoRefreshes = interval(GATEWAY_REFRESH_INTERVAL)
  .pipe(
    startWith(0),
    takeUntil(this.stopAutoRefresh)
  );

Then you can join these two signals toghether with merge, and call the API you need:

merge(
  forceRefresh,
  autoRefreshes
).pipe(
  exhaustMap(() => this.fetchAllData())
).subscribe(/* ... */)

Upvotes: 1

Barremian
Barremian

Reputation: 31125

You could send the delay as a parameter to the function and use RxJS timer() as the source observable instead of interval().

Try the following

Controller

autoRefreshGateways(delay = 5000, interval = 5000) {     // <-- default: trigger refresh after 5s and refresh every 5s
  timer(delay, interval).pipe(
    startWith(0),
    takeUntil(this.stopAutoRefresh),
    exhaustMap(() => this.fetchAllData())
  ).subscribe(
    (gateways) => {
      this.gateways = gateways;
    },
    () => {
      this.notificationsService.error(this.translateService.instant('zerotrust.gateway.list.error'), '')
    }
  );
}

Now you could call the function accd. to your requirement.

From UI input

...
<!-- trigger auto refresh immediately and refresh every 5s -->
<button (mouseup)="autoRefreshGateways(0)">Auto refresh</button>

From some other functions in controller

someFunc() {
  ...
  this.autoRefreshGateways();     // <-- trigger auto refresh after 5 seconds and refresh every 5s (default)
};

someOtherFunc() {
  ...
  this.autoRefreshGateways(3000, 10000);     // <-- trigger auto refresh after 3s and refresh every 10s
}

Upvotes: 0

Guilhermevrs
Guilhermevrs

Reputation: 2369

I would suggest the usage of a Subject that would combine with the interval. If either the interval or the subject emits, you then trigger the thing.

forceTrigger$ = new Subject();

autoRefreshGateways() {
  return combineLatest(
      interval(GATEWAY_REFRESH_INTERVAL),
      this.forceTrigger$.pipe(startWith(true))
    )
    .pipe(
      startWith(0),
      takeUntil(this.stopAutoRefresh),
      exhaustMap(() => this.fetchAllData())
    ).subscribe(
      (gateways) => {
        this.gateways = gateways;
      },
      () => {
        this.notificationsService.error(this.translateService.instant('zerotrust.gateway.list.error'), '')
      }
    );
}

// Example of forcing the trigger

onUIAction() {
  this.forceTrigger$.next(true);
}

Upvotes: 0

Related Questions