Rxjs poll object details first then repeated poll based on an object's status if needed

Viewed 90

I would like to know the best practice on doing the following in angular RxJS.

  1. on page load, I need to http get the details of an object
  2. based on the status of the object, I need to either repeatedly poll the status of the object until it is READY, if it is not ready. Or stop polling if it is ready.
  3. The status of the object can be changed from ready to not ready, or not ready to ready at any time. This can be set from the poll result, or set by the user on demand when a user wants.

I have tried something similar to the following, but feel it is not the best solution:

this.http.getObjectDetails(this.id).subscribe()

timer(1000, 1000)
      .pipe(
        filter(() => this.object.status != 'READY'),
        concatMap(() => {
          return this.http.checkObjectStatus(this.id)
        })
      ).subscribe()

First, it does not concat the two subscriptions, and secondly, I am not sure it can handle the situation that the status changed from ready to not ready.

Thanks

2 Answers

You can use the expand operator for a simple "conditional repeat" behavior.

this.http.getObjectDetails(this.id).subscribe()
let request = this.http.checkObjectStatus(this.id);

request.pipe(
  expand(
    res => {
      if (res.status == 'READY') {
        return empty();
      }
      else {
        return timer(1000).pipe(
          map(() => {
            return request
          })
        );
      }
    }
  ),
).subscribe(res => { });

also import

import { empty } from 'rxjs';
import { expand } from 'rxjs/operators';

You could do it with a function that calls itself recursively until the response is ready.

const { of, iif } = rxjs;
const { switchMap, tap, delay } = rxjs.operators;

const http = url => of({ STATUS: (Math.random() > .7) ? 'READY' : 'NOT READY' })

const getObjectDetails = (id) => http(`url/{id}`).pipe(
  tap(result => { console.log(result.STATUS); }),
  switchMap(result => iif(() => result.STATUS === 'READY', of(result), getObjectDetails(id)))
);

getObjectDetails(1).subscribe(result => { console.log('finished'); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.6.3/rxjs.umd.min.js"></script>

Related