Angular 17 - Trigger recurrent polling whenever a boolean variable becomes true and as long as it remains so

37 Views Asked by At

The situation is as follows: I have a websocket for communication between app and server. If the websocket were to break I would like to enable backup long polling until the websocket becomes active again.

I thought of creating a Signal boolean that changes state based on the connection/disconnection of the WS. If the WS is active I set the signal to true otherwise to false.

 WSStatus = signal(false);
 WS is up: this.WSStatus(true)
 WS go down: this.WSStatus(false)

I thought about doing something like this, but takeUntil waits for an Observable and I was unable to replace the Signal operation with an Observable

 this.startPolling(5000).pipe(takeUntil(!this.WSStatus())).subscribe()
 startPolling(interval: number = 5000): Observable<string> {
  
    return timer(0, interval)
      .pipe(
        switchMap( () => { return this.myHttpRequest() })
      );
  }
2

There are 2 best solutions below

0
Lorenzo On BEST ANSWER

The purpose of the code is to have a backup to the websocket in case of problems, so when it is NOT active I run a long time polling on http protocol until the websocket becomes active again

This is the solution I found:

properties:

pollingDone = signal(false)
private timerDone$ = new Subject<boolean>();

ws connection:

...
openObserver: {
  next: (event) => {
    this.pollingDone.set(true);
  }
},
closeObserver: {
  next: (event) => {
    this.pollingDone.set(false);
  }
}
...

constructor

effect( () => {
  this.timerDone$.next(this.pollingDone())
  if(this.pollingDone() === false) {
    this.startPolling(5000).subscribe(val => this.store.dispatch(TablePageActions.load()))
  }
})

methods

startPolling(interval: number = 5000): Observable<any> {
  return timer(0, interval)
  .pipe(
    takeUntil(this.timerDone$)
  )
}

Maybe it's not stylistic, I had difficulty defining an observable boolean accepted by the takeUntil, anyway it seems the goal was achieved. I tried to hook directly into the openObserver and closeObserver Events but failed.

3
martin On

If you want to use Angular signal withing RxJS chain you need to convert it into Observable using toObservable provided by @angular/core/rxjs-interop:

Then you can use it within takeUntil()

takeUntil(toObservable(this.WSStatus))

Note, that you might need to provide Injector yourself because toObservable uses inject(Injector) by default which is I think available only in components constructor.