I am attempting to use inheritance to make a universal error handler for my services, but for some reason, when it gets to the error handler itself, 'this' is always seeming to be null, and I cannot figure out why. I can get into the error handler just fine, but I always get:
EXCEPTION: Uncaught (in promise): TypeError: Cannot read property 'http' of null
Any idea what I am missing/doing wrong? Not sure how 'this' can ever be null?
Here is my whole base class for a service:
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
@Injectable()
export class HttpServiceBase {
constructor(public http: Http) {
console.log('http', this.http); //just do this to prove that it is there - it is!
}
handleError(error: any): Promise<any> {
console.error('Application Error', error); //this logs fine
// TypeError: Cannot read property 'http' of null
this.http.get('/Account/IsLoggedIn')
.map(response => console.log('RESPONSE: ', response));
return Promise.reject(error.message || error);
}
}
And this is my inheriting class:
import 'rxjs/add/operator/toPromise';
import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';
import { HttpServiceBase } from './http-service.base';
import { Hero } from './hero';
@Injectable()
export class HeroService extends HttpServiceBase {
private headers = new Headers({ 'Content-Type': 'application/json' });
private heroesUrl = 'http://localhost:57569/Home/Heroes';
constructor(http: Http) { super(http); }
getHeroes(): Promise<Hero[]> {
console.log('getting heroes');
return this.http.get(this.heroesUrl + '-force-error') //so it will error out
.toPromise()
.then(response => response.json() as Hero[] )
.catch(this.handleError);
}
}
I am attempting to use inheritance to make a universal error handler for my services, but for some reason, when it gets to the error handler itself, 'this' is always seeming to be null, and I cannot figure out why. I can get into the error handler just fine, but I always get:
EXCEPTION: Uncaught (in promise): TypeError: Cannot read property 'http' of null
Any idea what I am missing/doing wrong? Not sure how 'this' can ever be null?
Here is my whole base class for a service:
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
@Injectable()
export class HttpServiceBase {
constructor(public http: Http) {
console.log('http', this.http); //just do this to prove that it is there - it is!
}
handleError(error: any): Promise<any> {
console.error('Application Error', error); //this logs fine
// TypeError: Cannot read property 'http' of null
this.http.get('/Account/IsLoggedIn')
.map(response => console.log('RESPONSE: ', response));
return Promise.reject(error.message || error);
}
}
And this is my inheriting class:
import 'rxjs/add/operator/toPromise';
import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';
import { HttpServiceBase } from './http-service.base';
import { Hero } from './hero';
@Injectable()
export class HeroService extends HttpServiceBase {
private headers = new Headers({ 'Content-Type': 'application/json' });
private heroesUrl = 'http://localhost:57569/Home/Heroes';
constructor(http: Http) { super(http); }
getHeroes(): Promise<Hero[]> {
console.log('getting heroes');
return this.http.get(this.heroesUrl + '-force-error') //so it will error out
.toPromise()
.then(response => response.json() as Hero[] )
.catch(this.handleError);
}
}
Share
Improve this question
asked Dec 29, 2016 at 19:32
naspinskinaspinski
34.7k38 gold badges119 silver badges176 bronze badges
3 Answers
Reset to default 4For methods that are supposed to be used as callbacks it is remended to bind them to the context on construction. In TypeScript this is achievable via class field and arrow method:
constructor(public http: Http) {}
handleError = (error: any): Promise<any> { ... }
As opposed to binding on method call, this eliminates the possibility of incorrect context.
A more preferable way may be:
constructor(public http: Http) {
this.handleError = this.handleError.bind(this);
}
handleError(error: any): Promise<any> { ... }
It does the same thing but has better testability because it allows to spy/mock HttpServiceBase.prototype.handleError
before class instantiation.
It happens because you are passing the handleError as a function to the catch function. And when it is called it will have a different this object.
You can pass an arrow function to catch preserve the same context.
.catch(error => this.handleError(error));
You have to keep in mind that even if handleError is defined as a method on a class it still behaves as any other function would do.
Any chance this fixes it?
.catch(this.handleError.bind(this));