Reputation: 271
I'm trying to understand how passing of values or errors works from one component to the other. In my case I want to pass an error from the service to the component, and I have nested methods.
This will be a dummy example. This is the method in the Service which throws an error.
public serviceMethod(value1: Class1): Observable<Interface1>{
return new Observable(result => {
this.method1(class1) // this method throws an error and returns an number
.subscribe(decimalValue => this.method2(decimalValue) // this method does an error check and returns an Interface1 type
.subscribe(value2 => this.method3(value2, result, decimalValue)), error1 => throwError(error1)
)
})
}
Since method1 throws an error, error1 will be thrown too. Now what I want to do, is to pass somehow either a value or the error from the service to the method in another Component.
This is how the method in the other component will be implemented:
public methodInTheComponent = async () =>{
this.service.serviceMethod(valueOfClass1).subscribe(result => concole.log(result), error2 => console.log(error2));
}
Now, when I run this I just get the output of the error1 thrown, but not that of error2.
The reason for this is that the error is thrown from method1, and it didn't reach the other methods 2 and 3 to return an error result.
One solution which I thought of is using a boolean variable in the service.
Like errorThrown = true and then pass this to the component. Then I could do an if check in the subscribtion.
If the errorThrown is true, error2 should be thrown too.
I'm not sure if this is a good solution! One problem is that I don't know how to send this errorThrown to the Component!
Any suggestion or idea of what could be a possible good solution?
Upvotes: 0
Views: 2398
Reputation: 1202
Inner Observables won't execute when the outer ones fail. So in your case, if method1 throws an error, it won't execute method2 and method3. But if you want to continue executing the inner obseravbles, you have to catch the errors and return them as normal values for the execution to continue.
Modify you service class as below to catch and handle errors:
...
import { of } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class MyService {
method1() {
const obs;
// perform your logic and store the Observable in obs object
/**
* catch the error and convert it to a normal observable
* for execution of inner observable to continue
*/
return obs.pipe(catchError(err => of(err)));
}
// implement method2 and method3 in similar fashion
...
serviceMethod() {
return this.method1().pipe(
concatMap(val1 => {
console.log('result of method1: ', val1);
return this.method2();
}),
concatMap(val2 => {
console.log('result of method2: ', val2);
return this.method3();
})
);
}
}
Note that I have used concatMap
rxjs operator for observables dependent on one another because creating nested subscription is an anti-pattern and is not advisable to use. concatMap
will subscribe the inner observables automatically for you, so don't manually subscribe on it. For more information on concatMap
, check this article.
Now in your component class, subscribe to the serviceMethod
from service class as below:
this.service.serviceMethod().subscribe(
val => {
console.log("End result: ", val);
},
err => {
console.error("Error -> ", err);
}
);
Now you can execute the inner observables even if the outer ones throw error. For the complete example, refer to this Stackblitz project. Open the console of renderer on right side to view the results.
Upvotes: 1