Charlie
Charlie

Reputation: 1746

RXJS Repeat query until a condition is met?

I'm using an API that returns only a limited number of results, say 100.

I'd like to repeat a query until the return result set is < 100 which would mean I've got the last result.

So it would go like this:

  1. Make query
  2. Is result set less than limit? If so, do again and append results.
  3. Once result set is less than limit, emit the final result.

Upvotes: 19

Views: 32123

Answers (4)

ebrehault
ebrehault

Reputation: 2601

We can also use the repeat operator:

this.queryData().pipe(
    repeat(),
    filter(data => this.checkLimit()),
    take(1)
).subscribe(result => console.log(result));

Note: the take(1) is needed to stop the repeat loop.

If we need a delay between retries, we can do:

repeat({delay: 1000})

Upvotes: 30

ZahiC
ZahiC

Reputation: 14687

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

Just for the example, instead of a result set I changed the query to return a number. The following keep querying until the retrieved number is less than 100

const { defer, empty } = rxjs;
const { expand, toArray} = rxjs.operators;

const query$ = defer(async () =>  Math.floor(Math.random()*1000));
   
query$
  .pipe(
    expand(result => result < 100 ? empty() : query$),
    toArray()
  )
  .subscribe(console.log);
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>

Upvotes: 21

Ren&#233; Winkler
Ren&#233; Winkler

Reputation: 7058

 stop$: Subject = new Subject();

 query$.pipe(takeUntil(this.stop$)).subscribe( result => {
    if(result < limit) 
       this.stop$.next();
       this.stop$.complete();
     }
   else {
      process result, i.e append somewhere...
   }
 });

Note his is the RxJs 6 syntax. For readability you can extract the subscribe logic in a method.

Maybe working with takeWhile is easier in this case:

doQuery: boolean = true;

 query$.pipe(takeWhile(()=> this.doQuery).subscribe( result => {
    if(result < limit) 
       this.doQuery = false;
     }
   else {
      process result, i.e append somewhere...
   }
 });

Upvotes: 6

Suresh Kumar Ariya
Suresh Kumar Ariya

Reputation: 9754

You can also use RXJS Interval with TakeWhile operator. Here is the sample code

In Component:

return Observable
  .interval(250)
  .flatMap(() => this.getQueryData())
  .takeWhile(data => this.checklimit(data))
  .subscribe(result => console.log(result);

getQueryData(){
   // HTTTP API call 
}

checklimit(){
  // return true/false
}

Upvotes: 6

Related Questions