There is a function that must run 3 requests in a row, and it is not possible to know how many of them failed or succeeded. If the request fails, sending requests should stop and the user should click an ignore button. After pressing the button, the execution of missed requests must be continued.
I hope you can help me, how can I handle this situation.
Thanks in advance.
requests = {
X: "xyz.com"
Y: "abc.com"
Z: "qwe.com"
}
I tried to implement it with following:
from(Object.values(requests))
.pipe(
concatMap((action$: Observable<any>) => {
return action$.pipe(
map(response => response),
catchError(() => {
this.hasError = true;
return of(undefined);
}));
}),
takeWhile(() => !this.hasError),
scan((resp1, resp2) => resp1.concat(resp2), []),
)
.subscribe(
value => {
console.log('value =', value);
},
error => {
console.log('error = ', error);
},
() => {
console.log('COMPLETE');
}
);
This is running until the first request fails, but it doesn't continue after that.
I tried to find a waitUntil operator, but unfortunately there is not found.
For example:
- How it is working now:
1. X request status -> 200
2. Y request status -> 404 - So in this case complete shutdown occurs ( by the takeWhile ) and no continuation occur after setting the "hasError" value to "false"
FYI: The next request should be the Z, after clicking on the "ignore" button.
- How it should work:
Example #1:
1. X request status -> 200
2. Y request status -> 404 - Wait until the user clicks on the "ignore" button
3. Click on the "ignore" button
4. Z request status -> 200
5. All three values arrive in the "subscribe" section, so one value should be undefined and two should be the requested response values.
Example #2:
1. X request status -> 404 - Wait until the user clicks on the "ignore" button
2. Click on the "ignore" button
3. Y request status -> 200
4. Z request status -> 404 - Wait until the user clicks on the "ignore" button
5. Click on the "ignore" button
6. All three values arrive in the "subscribe" section, so two value should be undefined and one should be the requested response value.
I hope you can help me, how can I handle this situation.
Thanks in advance.
CodePudding user response:
Your code is pretty close. Instead of returning of()
inside catchError
, you should return an observable that emits when the user has confirmed:
items$ = from(this.itemIds).pipe(
concatMap(id => this.itemService.get(id).pipe(
catchError(() => this.promptUser(id).pipe(map(() => undefined)))
)),
reduce((all, item) => all.concat(item), [])
);
Per your description, I think you want reduce
instead of scan
. reduce
will only emit once, whereas scan
will emit each time it receives a value.
Here's a StackBlitz demo.
CodePudding user response:
- create
ignore$
Subject catchError
returnignore$.pipe(take(1))
to wait user click
const ignore$ = new Subject<undefined>();
function click() {
ignore$.next(undefined);
}
from(Object.values(requests)).pipe(
concatMap((action$: Observable<any>) =>
action$.pipe(
map(response => response),
catchError(() => ignore$.pipe(take(1))),
)
),
scan((p, c) => p.concat(c), []),
).subscribe(...);