Reputation: 907
I defined a simple function that will open a MatSnackBar
and display the error message when a get request returns any error
handleError(err: HttpErrorResponse) {
this.snackBar.open(err.message)
return throwError(err)
}
So when I subscribe to an observable in the constructor I pass the above function to catchError
constructor(private snackBack: MatSnackBar) {
...
this._obv$ = this.myService.getTypes().pipe(
catchError(this.handleError)
)
...
When the error is triggered the err
passed to the handleError
is correct but this.snackBar
is undefined
.
The problem disappear when I use the handleError
function like this
this._obv$ = this.myService.getTypes().pipe(
catchError(err => this.handleError(err)
)
What's the difference and why is the snackBar
instance undefined
?
Upvotes: 2
Views: 1879
Reputation: 8022
The issue is that a when a function is called on an object, the object is implicitly passed as that's functions context (its this
). Sometimes you'll see this invocation style called a method rather than a function.
Methods are implicitly given the object whose properties they're allowed to operate on. You can, however, make this relationship explicit.
this.handleError
, doesn't call the function, it just passes a reference to it. Now catchError
doesn't know that it needs to call this.handleError(err)
instead of handleError(err)
.
In general, if a function uses the this
keyword, then the caller is responsible for supplying the this
context. Using dot notation makes this pretty intuitive but causes strange behaviour in the corner cases.
One fix is to use a lambda function to do that step for you. Lamda function (using arrow =>
syntax) always retain the context relative to where they are defined. So in this case, this
refers to what you expect.
Another solution is to bind the right object to the function call (which lets you call the function as a method on the bound object). This workaround is more robust in some cases as it lets you bind any context to a function. In this case, however, you're just binding the current context.
like this:
constructor(private snackBack: MatSnackBar) {
...
this._obv$ = this.myService.getTypes().pipe(
catchError(this.handleError.bind(this))
)
...
Upvotes: 3