What I want to do is the following:
I originally tried to do it in the catchError
inside the function, but that didn't work...it kept on going no matter what. Then I thought to throw it to the error
in the subscribe
and that mostly works except that I can't continue.
Any hope please? Trying to wrap my head around rxjs and I'm learning a lot...but don't know if I can get around this.
Here's a stackblitz.
export class AppComponent {
constructor(private postService: PostService, public dialog: MatDialog) {}
startEverything(): void {
const sameFunc = (id1: number, id2: number) => {
return this.postService.addPost(id1).pipe(
switchMap((post: Post) => {
return this.postService.getPosts().pipe(take(1));
}),
switchMap((posts: Post[]) =>
this.postService.getPost(id2).pipe(
map((post) => post),
// catch any errors here and throw to down below
catchError((error) => {
console.log('error: ', error);
throw new Error(error);
})
)
),
switchMap((queryId: string) =>
this.postService.deletePost(9).pipe(catchError(() => of(undefined)))
)
);
};
// creating an array of three function calls, second one will fail
const requests = [sameFunc(1, 1), sameFunc(2, 999), sameFunc(3, 3)];
from(requests)
.pipe(
// run three function calls sequentially
concatAll()
)
.subscribe({
next: (x) => console.log('Observer got a next value: ' + x),
error: (err) => {
console.error('Observer got an error: ' + err);
// pop up dialog here with STOP/CONTINUE
const dialogRef = this.dialog.open(DialogContentExampleDialog);
dialogRef.afterClosed().subscribe((result) => {
console.log(`Dialog result: ${result}`);
if (result) {
// continue with next concatAll() <== can I do this??
}
});
},
complete: () => {
console.log('Observer got a complete notification');
},
});
}
}
EDIT: Ah okay, I just realized that the order isn't happening the way I wanted. What I want is this:
* post1
* get1
* delete1
* post2
* get2 <--- this fails
* pop up dialog
===================
* if continue
* delete2
* post3
* get3
* delete3
===================
* if stop
* delete2
And there can be any number of posts, not just 3 and any can fail on the get. Is this possible?
Probably there is a better way but you could handle your scenario with the following example:
startAll(): void {
const first$ = of(1);
const third$ = of(3);
const fourth$ = of(4);
const second$ = of(2).pipe(
map((val) => {
if (val === 2) throw new Error('an error occurred...');
return val;
})
);
this._handleRequests([first$, second$, third$, fourth$]);
}
private _handleRequests(requests: Observable<number>[]): void {
let _continue = true;
from(requests)
.pipe(
concatMap((obs$) =>
obs$.pipe(
mergeMap((value) => of(value)),
catchError(() =>
this._handleDialog().pipe(tap((v) => (_continue = v)))
),
takeWhile(() => _continue === true)
)
)
)
.subscribe((v) => console.log('Subscribed ', v));
}
private _handleDialog(): Observable<boolean> {
const dialogRef = this.dialog.open(DialogContentExampleDialog);
return dialogRef.afterClosed();
}
With the rxjs concatMap
operator, you wait for the observable to complete in order to handle the next one, so it executes sequentially. Additionally, by making use of takeWhile
, you could set the necessary condition for stopping the whole emitted values, so in this, the condition is given by the user through the material dialog.
The output for when the user decides to continue would be:
// Subscribed 1
// Subscribed true
// Subscribed 3
// Subscribed 4
When the user decides to stop, then the output will be:
// Subscribed 1