antonyboom
antonyboom

Reputation: 1181

Use material2 snackbar as error handler for angular2

I'm trying to set snackbar from material2 as error catcher for angular2 services. Seems to me I did everything correct but still getting an error

EXCEPTION: Uncaught (in promise): TypeError: Cannot read property 'notify' of undefined TypeError: Cannot read property 'notify' of undefined

This is my services with my catcher:

import { Injectable } from '@angular/core';
import {Headers, Http, RequestOptions} from '@angular/http';

import 'rxjs/add/operator/toPromise';
import {Observable} from 'rxjs/Rx';
import {MdSnackBar, MdSnackBarConfig, MdSnackBarRef} from '@angular/material';

@Injectable()

export class AppServices {

  private api = 'app/endpoint';
  private headers = new Headers({ 'Content-Type': 'application/json' });
  private options = new RequestOptions({ headers: this.headers });

  constructor(
    private http: Http,
    private snackbar: MdSnackBar
  ) { }

  getConfigs(): Promise<any> {
    return this.http
      .get(this.api + "/confs")
      .toPromise()
      .then(response => response.json() as Array<Object>)
      .catch(this.handleError)
  }

  // ==============
  // errors handler
  // ==============

  notify (status: any, text: any) {
    this.snackbar.open(status, text, {
      duration: 3000
    });
  }

  public handleError(error: Response) {
    this.notify(error.status, error.statusText);
    return Observable.throw(error.json() || 'Server error');
  }
}

So when catcher gets an error instead of snakebar I get the error in console that my function is undefined.

Could somebody explain me where my mistake is? Thanks in advance

Upvotes: 1

Views: 2580

Answers (1)

Steve G
Steve G

Reputation: 13397

You are losing scope within your .catch() statement. When the asynchronous .catch() method was executing, it is attaching it's own scope to this.

Using an arrow function like so:

.catch((err)=>{this.handleError(err);})

Will ensure that your scope is maintained through the asynchronous method calls and typically good practice these days with TS to avoid this hell.

The arrow function syntax uses “lexical scoping” to figure out what the value of this should be. Lexical scoping is fancy way of saying it uses this from the surrounding code.

If you're interested in reading more about arrow functions and lexical scoping, this is a good article.

The interesting thing to note is that the this value (internally) is not actually bound to the arrow function. Normal functions in JavaScript bind their own this value, however the this value used in arrow functions is actually fetched lexically from the scope it sits inside. It has no this, so when you use this you’re talking to the outer scope.

Upvotes: 6

Related Questions