Reputation: 7269
I need:
Now the code is look like:
ids = [{valid: true, id: 1}, {valid: true, id: 2}, {valid: true, id: 3}, {valid: false, id: 4}]
constructor(httpClient: HttpClient) {
from(this.ids)
.pipe(
map(obj => ({...obj, id: obj.id + 5})),
concatMap(obj => {
console.log('concat map');
if (obj.valid === false) {
return throwError('not valid');
} else {
return httpClient.get(`https://jsonplaceholder.typicode.com/todos/${obj.id}`);
}
})
)
.subscribe(
result => console.log('success', result),
result => console.log('error', result),
() => console.log('complete')
);
}
Here is stackblitz: https://stackblitz.com/edit/angular-5vwbjg
So what I want is to not to send the request if object is not valid. And I want to process next
id from initial observable, only if handling of previous is ended. So I want flow like:
I handled this only by extending concatMap code. Is it somehow possible to extract this check to another pipeable operator before the concatMap
? So concatMap
body will be simpler.
I tried mergeMap operator like:
mergeMap(obj => {
console.log(obj);
if (obj.valid === false) {
return throwError('not valid');
} else {
return of(obj);
}
}),
And I got this in console:
This is not correct result. I expect 3 requests and then 1 error. Expected result:
Also maybe there is more beautiful way to describe check function in my case? Any ideas? Without that if
with 2 branches.
I think that I misunderstood that point. from(this.ids)
emits values anyway. It does not wait concatMap
or map or any other operator. On that moment, when new value is emitted in from(this.ids)
(it will be before concatMap
finishes) it proccess whole chain: map
+ concatMap
. What I need is somehow say rxjs to process 2nd emitted value, after concatMap
finished handling 1st. Then it should process 3rd emitted value, after concatMap
finished handling 2nd e t c.
A bit extended example is here: https://stackblitz.com/edit/angular-ovffm4?file=src/app/app.component.ts
Here I have 2 client checks and 1 server response.
Here is what I see in console:
map
first check true
second check 6
make request
map
first check true
second check 7
map
first check true
second check 8
map
first check true
second check 9
map
first check true
second check 10
map
first check false
success {userId: 1, id: 6, title: "qui ullam ratione quibusdam voluptatem quia omnis", completed: false}
make request
success {userId: 1, id: 7, title: "illo expedita consequatur quia in", completed: false}
complete
How to change my observable so it will be like:
map
first check true
second check 6
make request
success {userId: 1, id: 6, title: "qui ullam ratione quibusdam voluptatem quia omnis", completed: false}
map
first check true
second check 7
make request
success {userId: 1, id: 7, title: "illo expedita consequatur quia in", completed: false}
map
first check true
second check 8
map
first check true
second check 9
map
first check true
second check 10
map
first check false
complete
Upvotes: 1
Views: 519
Reputation: 6441
For starters, i think you misunderstood how error handling works in rxjs. The error handling function you pass as 2nd parameter to the subscribe function will never be called more than once. Once an observable encounters one single error, it is completed and no longer functions. So you can not use that function to catch multiple errors.
http://reactivex.io/documentation/operators/subscribe.html
An Observable calls this method to indicate that it has failed to generate the expected data or has encountered some other error. This stops the Observable and it will not make further calls to onNext or onCompleted. The onError method takes as its parameter an indication of what caused the error (sometimes an object like an Exception or Throwable, other times a simple string, depending on the implementation).
You will never be able to handle it this way.
This might be an alternative way:
https://stackblitz.com/edit/angular-wbu3tv
Snippet:
concatMap(obj => {
console.log(obj);
if (obj.valid === false) {
return of({
response: null,
success: false
});
} else {
return httpClient.get(`https://jsonplaceholder.typicode.com/todos/${obj.id}`).pipe(map(response => {
return {
response: response,
success: true
}
}));
}
})
So basically, instead of using throwError, i return an object that indicates wether a request was executed, and the response if it was executed.
Upvotes: 0