Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rxjs poll for data on timer and reset timerwhen manually refreshed

Tags:

rxjs

I am using the following libraries in the relevant application: Angular 4.x, ngrx 4.x, rxjs 5.4.x

I have an api that I need to poll every 5 minutes. The user is also able to manually refresh the data. That data is stored in an ngrx store. I am using ngrx effects so the data is retrieved by dispatching an action of type 'FETCH'.

I want to setup a rxjs stream where it will dispatch the 'FETCH' action to the ngrx store. It will be a sliding 5 minute timer that resets when the user manually updates the store. The stream should initially emit a value when subscribed.

I'm not sure how I can reset the timer. In plain javascript I would do something like the following:

console.clear();
let timer;
let counter = 0;

function fetch() {
  console.log('fetch', counter++);
  poll();
}

function poll() {
  if (timer != null) {
    window.clearTimeout(timer);
  }
  timer = window.setTimeout(() => {
    console.log('poll');
    fetch();
  }, 5000);
}

function manualGet() {
  console.log('manual');
  fetch();
}

fetch();
<button onClick="manualGet()">Get Data</button>

Question: How do I emit on an interval that is reset when another stream emits like the example again?

like image 415
bygrace Avatar asked Oct 15 '25 07:10

bygrace


1 Answers

You want two components to your stream – a timer and some user input. So let's start with the user input. I'll assume some button which can be clicked:

const userInput$ = Observable.fromEvent(button, 'click');

Now we want to start a timer which resets everytime userInput$ emits. We can do that using

userInput$.switchMap(() => Observable.timer(0, 5000));

However, we also want this stream to start without the user having to first click the button. But that's also not a problem:

userInput$.startWith(null);

Now we put it all together:

Observable.fromEvent(button, 'click')
    .startWith(null)
    .switchMap(() => Observable.timer(0, 5000))
    .subscribe(() => dispatchFetch());

Note that I am following your examples of using a 5 second timer, not a 5 minute timer (which you mentioned in the question.)

like image 195
Ingo Bürk Avatar answered Oct 18 '25 06:10

Ingo Bürk