1

Setup

  • Angular 13.2.0
  • Ngrx 13.0.2
  • Backend: Spring Boot

Goal

I want to continually get the data from the backend. The data is changing and i want to reflect those changes in the angular-app.

What works so far

pollingfetchEntities$ = createEffect(
    () => ({ scheduler = asyncScheduler, stopTimer = EMPTY } = {}) =>
      this.actions$.pipe(
        // Filter action type
        ofType(DoctransActions.fetchEntities),
        // Get the polling interval
        switchMap(() =>
          // Start polling
          timer(0, 3000, scheduler).pipe(
            // Stop the polling (used only in testing)
            takeUntil(stopTimer),
            switchMap(() =>
              this.http.get<DoctransResponse>(`${this.apiUrl}/someurl`).pipe(
                map(response => {
                  return action to set entities
                }),
                catchError((err) => {
                  return action for error
              )
            )
          )
        )
      )
  );

Question

Is there a better way for doing this? Maybe i am missing a complete other pattern?

Update 1

Investigating the websocket approach. From here: https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-websocket

it says

Latency alone is not a deciding factor. If the volume of messages is relatively low (for example, monitoring network failures) HTTP streaming or polling can provide an effective solution. It is the combination of low latency, high frequency, and high volume that make the best case for the use of WebSocket. Blockquote

The angular-app will run in the spring-boot-backend. So there wont be any latency. But i dont need real time data (in ms or s). 1 update every 30 sek or every min is good enough.

So maybe HTTP streaming or polling is enough? Dont know this yet. Anyone has some experience with it?

Solution

Solved with

  • backend: spring webflux
  • angular: EventSource
Hesk
  • 307
  • 4
  • 16
  • As you're implementing an Effect, this code would start a new observable performing the polling requests for every time the fetchEntities action is invoked. I'd suggest a service instead. – Mikkel Christensen Mar 14 '22 at 08:51

3 Answers3

0

The best way is to use websocket.

import { webSocket } from "rxjs/webSocket";
const subject = webSocket('ws://localhost:8081');
 
subject.subscribe();
 
subject.next({message: 'blablabla'});
 
subject.complete();

You can create a websocket service to manage websocket in your Angular application, as well.

See rxjs documentation for more details.

Pterrat
  • 1,682
  • 11
  • 18
  • Their use of polling suggests their back-end may not support a websocket connection for this endpoint. – Mikkel Christensen Mar 14 '22 at 08:48
  • Backend is also in our hand. We can do here as we want. I just started my journey into angular so this was my first try of "getting data continually" :) Will try the websocket. Thanks – Hesk Mar 14 '22 at 09:18
0

This is fine if you want to poll for your data. Another option is to use websockets that way the servers can send data to the client.

timdeschryver
  • 14,415
  • 1
  • 19
  • 32
0

Websocket is the best way to achieve this but sometimes we can't able to use it in our projects because of backend is not supporting etc...

If the case is you can't use websockets, and you want to poll data from your server another way to achieve it is using interval from rxjs

loadEntities$ = createEffect(() =>
  this.actions$.pipe(
    ofType(fromEntityActions.loadEntities),
    switchMap(() => interval(1000)),
    map(() =>
      fromEntityActions.loadEntitiesSuccess({
        data: [
          {
            id: Math.random() > 0.5 ? 1 : 2,
            name: "Sefa",
            code: "Sefa"
          }
        ]
      })
    )
  )
);

You can try this code, Math.random is just for testing purposes to see if its really changing at 1000ms interval.