Reputation: 1107
I have the following requirement:
The context is a guard in Angular which uses canActivate() returning an Observable<boolean>
I want to avoid following construction in the guard (pseudo code):
// the actions to check
var actions = ['x', 'y', 'z'];
canActivate() : Observable<boolean> {
return this.performAction(actions[0]).subscribe(result => {
if(result){
this.performAction(actions[1]).subscribe(result2 => {
if(result2){
this.performAction(actions[2]).subscribe(result3 => {
...
};
}
});
}
//result = false;
};
}
Upvotes: 4
Views: 1399
Reputation: 1159
Updated answer for rxjs 7.x (7.5.4)
This answer does also satisfy the OP's requirement of:
- further observables should not have to proceed
To get this working I had to use a new parameter added to the takeWhile operator(rxjs 6+) which returns the value that caused the takeWhile operator to complete the observable.
Working code example: https://stackblitz.com/edit/rxjs5-85mw81?file=index.ts
const arrayOfValues = ['x', 'y', 'z'];
const performAction = (action): Observable<boolean> => {
if (action === 'y') {
return of(false);
}
return of(true);
}
const observable = of(...arrayOfValues).pipe(
concatMap(a => performAction(a)),
takeWhile(result => result !== false, true),
takeLast(1));
observable.subscribe(console.log);
Upvotes: 0
Reputation: 96891
You can do it like this:
import { Observable, Subject, ReplaySubject } from 'rxjs';
const actions = ['x', 'y', 'z'];
const performAction = (action): Observable<boolean> => {
if (action === 'y') {
return Observable.of(false);
}
return Observable.of(true);
}
const observable = Observable.from(actions)
.concatMap(a => performAction(a))
.multicast(new ReplaySubject(1),
s => s.takeWhile(result => result !== false).concat(s.take(1))
);
observable.subscribe(console.log);
See live demo (open console): https://stackblitz.com/edit/rxjs5-hnzwtt?file=index.ts
The most important part is the multicast
operator that passes through everything until it receives false
. Then this false
value is the last one before completing the chain (thanks to concat
).
The output is:
true
false
Upvotes: 1