I just finished implementing data polling using ngrx effects. For those unfamiliar with ngrx, it is a popular library for implementing the Redux pattern in Angular applications.

To implement data polling with ngrx effects, you can create an effect that listens for a specific action, such as a POLL_DATA action. When this action is dispatched, the effect can perform an HTTP request to retrieve the data from a remote server, and then dispatch a new action with the data.

You can use the @Effect decorator to create an effect that listens for specific actions. The @Effect decorator takes an options object as an argument, which allows you to specify the action that the effect should listen for and the effect’s behavior.

For example, you might create an effect that listens for the POLL_DATA action and performs an HTTP request to retrieve the data like this:

@Injectable()
export class PollingEffects {
  pollData$: Observable<Action> = this.actions$.pipe(
    ofType(POLL_DATA),
    switchMap(() =>
      this.http.get('/api/data').pipe(
        map((data) => ({ type: DATA_RECEIVED, payload: data })),
        catchError(() => of({ type: DATA_REQUEST_FAILED }))
      )
    )
  );
}


This effect listens for the POLL_DATA action and then performs an HTTP request using the HttpClient service. If the request is successful, it dispatches a DATA_RECEIVED action with the received data as the payload. If the request fails, it dispatches a DATA_REQUEST_FAILED action.

To ensure that the data is polled at regular intervals, you can use the interval operator from the RxJS library. You can modify the effect above to poll the data every 10 seconds like this:

@Injectable()
export class PollingEffects {
  pollData$: Observable<Action> = this.actions$.pipe(
    ofType(POLL_DATA),
    switchMap(() => interval(10000)),
    switchMap(() =>
      this.http.get('/api/data').pipe(
        map((data) => ({ type: DATA_RECEIVED, payload: data })),
        catchError(() => of({ type: DATA_REQUEST_FAILED }))
      )
    )
  );
}

In this modified version of the effect, the interval operator is used to emit a value every 10 seconds (10000 milliseconds). The effect then uses the switchMap operator to perform an HTTP request every time the interval emits a value.

To stop the data polling, you can simply dispatch a new action that the effect can listen for and respond to.

For example, you might create a STOP_POLLING action that the effect can listen for and use to stop polling the data. You can modify the effect above to stop polling when the STOP_POLLING action is dispatched like this:

@Injectable()
export class PollingEffects {
  pollData$: Observable<Action> = this.actions$.pipe(
    ofType(POLL_DATA),
    switchMap(() =>
      interval(10000).pipe(takeUntil(this.actions$.pipe(ofType(STOP_POLLING))))
    ),
    switchMap(() =>
      this.http.get('/api/data').pipe(
        map((data) => ({ type: DATA_RECEIVED, payload: data })),
        catchError(() => of({ type: DATA_REQUEST_FAILED }))
      )
    )
  );
}

In this modified version of the effect, the takeUntil operator is used to stop the data polling when the STOP_POLLING action is dispatched. The takeUntil operator takes an observable as an argument and completes the source observable (in this case, the interval observable) when the argument observable emits a value.

To use this modified effect, you can dispatch the POLL_DATA action to start polling and the STOP_POLLING action to stop polling.

To create a unit test for the data polling effect using the TestScheduler from the RxJS library, you can use the following steps:

First you have to modify your effect to use asyncScheduler like this:

@Injectable()
export class PollingEffects {
  pollData$: Observable<Action> = this.actions$.pipe(
    ofType(POLL_DATA),
    switchMap(() =>
      interval(10000, asyncScheduler).pipe(
        takeUntil(this.actions$.pipe(ofType(STOP_POLLING)))
      )
    ),
    switchMap(() =>
      this.http.get('/api/data').pipe(
        map((data) => ({ type: DATA_RECEIVED, payload: data })),
        catchError(() => of({ type: DATA_REQUEST_FAILED }))
      )
    )
  );
}

In this modified version of the effect, the interval operator is called with the asyncScheduler as the second argument. This causes the interval to use the asyncScheduler to schedule its emissions.

The asyncScheduler is a scheduler that schedules work asynchronously, using the JavaScript interval function. This can be useful if you want to simulate a delay in the data polling effect, or if you want to ensure that the effect is run outside the Angular zone.

I hope this helps clarify how to use the asyncScheduler with the data polling effect. Next you will add your unit tests file and follow the steps:

  1. Import the TestScheduler from the RxJS library. The TestScheduler is used to control the virtual time in the test;
  2. Create an instance of the TestScheduler and set up the test actions and expected results. To do this, you will need to define the actions that the effect should listen for and the expected results of the effect.
  3. Set up the dependencies for the effect under test. This will typically include any services or dependencies that the effect uses, such as the HttpClient service. You can use mock implementations of these dependencies to control their behavior in the test.
  4. Create an instance of the effect under test and pass in the dependencies.
  5. Pass TestScheduler instance into the effect that is under test. This will execute the effect with a virtual timer.

Here is an example of a unit test for the data polling effect using the TestScheduler:

@Injectable()
export class PollingEffects {

    pollData$ = createEffect(() => ({ scheduler = asyncScheduler} = {}) =>
    this.actions$.pipe(
      ofType(POLL_DATA),
      switchMap(() => interval(10000, asyncScheduler).pipe(
        takeUntil(this.actions$.pipe(ofType(STOP_POLLING)))
      )),
      switchMap(() => this.http.get('/api/data').pipe(
        map(data => ({ type: DATA_RECEIVED, payload: data })),
        catchError(() => of({ type: DATA_REQUEST_FAILED }))
      ))
    )
  );

}

To use the createEffect function from the ngrx library with the data polling effect, you can modify the effect like this:


The createEffect function takes a function that returns an observable as an argument, and returns an observable of actions. The function that is passed to createEffect should contain the logic for the effect.

In this modified version of the effect, the createEffect function is used to wrap the logic for the effect in a way that is compatible with the ngrx store. The effect listens for the POLL_DATA action and performs an HTTP request to retrieve the data every 10 seconds (10000 milliseconds) using asyncScheduler. If the request is successful, it dispatches a DATA_RECEIVED action with the received data as the payload. If the request fails, it dispatches a DATA_REQUEST_FAILED action.

I hope this helps clarify how to use the createEffect function with the data polling effect.

Using ngrx effects to implement data polling is a straightforward process. Essentially, you can create an effect that listens for a specific action, such as a POLL_DATA action, and performs an HTTP request to retrieve data from a remote server. The effect can then dispatch a new action, such as a DATA_RECEIVED action, with the received data as the payload.

To stop the data polling, you can simply dispatch a new action, such as a STOP_POLLING action, that the effect can listen for and use to stop the data polling process.

Unit testing this effect is a bit tricky but you got it!

Hope all the code examples help you!

Hope you enjoyed this article.