2

I'm using RxJS in an Angular project and I have a Subscription to an Observable that emits values at a regular interval.

In the same component, I'm also using RxJS (combined with the Angular http client) to make a web call and subscribe to it.

What I want to do is simple: when I make my web call and it has returned a result, I want to wait until the Subscription receives the next value before processing the result. Let's see it better with a code sample:

Suppose I have this Subscription that receives new values from an Observable at regular intervals:

tenantStatusSub: Subscription; 

Here's what I want to do, explained in the comment:

this.httpClient.get<any>(...).subscribe({ next: result => { /* I want to wait here for tenantStatusSub to receive a value before proceeding */ }, error: err => { //... } }); 

I'm sure there is a straightforward way to do this, but I'm still learning RxJS so I'm not sure what the best/cleanest way is.

2 Answers 2

2

I don't think you can wait for the tenantStatusSub-subscription itself. Yet you can wait for the next emission of the observable that the tenantStatusSub-subscription refers to. I suggest you to use switchMap() to chain your http-request directly to the observable that receives the continuous flow of emissions. What's more you can use first(), to trigger "unsubscribe" after the first value has arrived:

tenantStatusObs$: Observable<any> = observableThatReceivesAFlowOfValues; ngOnInit(): void { this.httpClient.get<any>('http://www.some-url.com').pipe( switchMap(resultFromApi => { return this.tenantStatusObs$.pipe( first(), // unsubscribes after the first value has been emitted tap(tenantStatus => { console.log('Tenant Status:', tenantStatus); console.log('Result from API:', resultFromApi); }) ) }) ) .subscribe(); } 
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this solution does exactly what I want
1

CombineLatest can do this but it's not great. If tenantStatusSub emits regularly within the time interval it takes to get a response, this will work. Even so, the answer with switchMap below (though a bit more complex) should be much more robust.

combineLatest([ tenantStatusSub, this.httpClient.get<any>(...) ]).pipe( skip(1), take(1) ).subscribe({ next: result => { // both values in result here }, error: err => { //... } }); 

Update:

Once you have your http response, acquire the next tenant status and merge the two values into a single output. Since the switch into tenantStatusObs$ is long-lived, you'll need to unsubscribe via take(1).

this.httpClient.get<any>(...).pipe( switchMap(httpRes => this.tenantStatusObs$.pipe( map(tenantStatus => ({ httpRes, tenantStatus }) )), take(1) ).subscribe({ next: ({ httpRes, tenantStatus }) => { // both values available here }, error: err => { //... } }); 

An Aside:

In this case you could write take(1) after either the map or the switchMap operator. They'd create the same output. Semantically, however, they have different meanings.

  • After map means: "At most one (paired) emission per tenantStatusSub emission"
  • After switchMap means: "At most one (paired) emission"

2 Comments

This doesn't do exactly what I want though, at least I think. I want to wait for the next result AFTER the http request has been done. This doesn't look like it guarantees that, it might get a value from tenantStatusSub before obtaining the http result, correct?
@Master_T, ah yeah, that's true. I've updated the original answer to work. I've also added another take with switchMap that should work.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.