How to Make One Observable Sequence Wait for Another to Complete Before Emitting

How to make one Observable sequence wait for another to complete before emitting?

A couple ways I can think of

import {take, publish} from 'rxjs/operators'
import {concat} from 'rxjs'

//Method one

var one = someObservable.pipe(take(1));
var two = someOtherObservable.pipe(take(1));
concat(one, two).subscribe(function() {/*do something */});

//Method two, if they need to be separate for some reason
var one = someObservable.pipe(take(1));
var two = someOtherObservable.pipe(take(1), publish());
two.subscribe(function(){/*do something */});
one.subscribe(function(){/*do something */}, null, two.connect.bind(two));

wait Until a second Observable emits

You want to run a second observable when a first observable emits a non-null value. To do this, use concatMap or switchMap after skipWhile.

ngOnInit() {
const init$ = new BehaviorSubject(null);

const source = new BehaviorSubject({profile:"me"});
const pipedSource = init$
.pipe(
skipWhile((res)=> res === null),
concatMap(() => source)
);

pipedSource.subscribe(val => console.log('first', val));

//init emits once
setTimeout(()=>{
init$.next(1);
},2000);

// a second subscription to source
setTimeout(()=>{
pipedSource.subscribe(val => console.log('second', val));
}, 3000);
}

Here I am subscribing to the init$ observable first, waiting for it to emit a non-null value, and then switching to the source observable.

DEMO: https://stackblitz.com/edit/angular-p7kftd

Wait for observable to give value to variable before trying to do something with it

Assuming someObservable$ is an observable for a HTTP request, move the code that relies on this.ref to be inside the subscription handler. Here's an example:

someObservable$.subscribe(response => {
this.ref = response;
// Do whatever work relies on this.ref here.
});

The subscription handler is fired once you receive a response from the HTTP request. So that should be the time to do the work needed. If this.ref is a variable for a template, then the template should take care of updating the view with the new value automatically.

Making one observable after the other one is complete

You shouldn't subscribe to the first observable, but instead use one more operator to finally subscribe to the second observable.
The operator you want is either mergemap or switchmap.

EDIT

Could you try this ?

this.router.events
.filter(event => event instanceof NavigationEnd)
.startWith({})
.pairwise()
.tap((events: [NavigationEnd, NavigationEnd]) => {
if (
this.breadcrumbs.length > 0 &&
events[0].url &&
events[0].url.split("?")[0] === events[1].url.split("?")[0]
) {
return;
}
let root: ActivatedRoute = this.activatedRoute.root;
this.breadcrumbs = this.getBreadcrumbs(root);

this.checkSetIsHomePage();
this.setBreadcrumbHeight();
})
.switchMap(() => this.breadcrumbService.additionalBreadcrumbs)
.takeUntil(this.destroy$)
.subscribe(breadcrumb => {
if (breadcrumb.index) {
this.breadcrumbs.splice(breadcrumb.index, 0, breadcrumb);
} else {
this.breadcrumbs.push(breadcrumb);
}

this.setBreadcrumbHeight();
});

What you do here is use the tap operator to manipulate your "this" on each emit, but you don't change the observable and you don't emit one yourself. Then you switch to the second observable, on each emit of the first.

Angular Observable wait for method to execute before return

Use switchMap like this

this.postService.addPost(post).pipe(
switchMap((newPost: Post) => {
if(selectedFilePaths.length !== 0) {
return this.imageService.uploadPostImages(newPost, selectedFilePaths).pipe(
map(() => newPost),
);
}
return of(newPost);
})
)


Related Topics



Leave a reply



Submit