最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - angular2 service base class inheritance - why is 'this' null? - Stack Overflow

programmeradmin0浏览0评论

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
Add a ment  | 

3 Answers 3

Reset to default 4

For 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));
发布评论

评论列表(0)

  1. 暂无评论