The mystery of 'this' being null in Angular 2 service base class inheritance

I'm trying to create a universal error handler for my services using inheritance, but I'm facing an issue where 'this' is always null in the error handler. I can access the error handler, but I keep getting the following error:

EXCEPTION: Uncaught (in promise): TypeError: Cannot read property 'http' of null

Any suggestions on what might be missing or wrong in my approach? It's puzzling how 'this' can be null.

This is the base class for my 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 here is the 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);
    }
}

Answer №1

When dealing with methods meant for use as callbacks, it is suggested to bind them to the context during construction. In TypeScript, one way to achieve this is by utilizing a class field and arrow method:

constructor(public httpClient: HttpClient) {}

handleError = (error: any): Promise<any> { ... }

Instead of binding during method call, this approach prevents incorrect context issues.

An even more preferable technique could be:

constructor(public httpClient: HttpClient) {
  this.handleError = this.handleError.bind(this);
}

handleError(error: any): Promise<any> { ... }

Although achieving the same result, this method offers improved testability as it enables spying/mocking on

HttpClientServiceBase.prototype.handleError
prior to class instantiation.

Answer №2

The reason for this behavior is because when passing handleError as a function to the catch block, it creates a new context for the function call. To maintain the original context, you can use an arrow function instead.

By using an arrow function in place of catch, you ensure that the context remains the same.

.catch(error => this.handleError(error));

It's important to note that even if handleError is part of a class definition, it will still be treated like any other function.

Answer №3

Is there a possibility that this will solve the issue?

.catch(this.handleError.bind(this));

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Activating the Submission of a File in a JQuery Form Plugin

Currently, I am using the JQuery Form Plugin to facilitate file uploads on my website. Instead of using a standard submit button, I would prefer to have a div element trigger the submission process. Here is the code I have attempted: $(document).on(&apo ...

Is there a way to use JQuery to dynamically generate a new select box with specific options?

I am looking to dynamically create a new select box based on the value selected in an existing select box using jQuery. Currently, the code we have implemented is not functioning correctly. <script src="http://code.jquery.com/jquery-1.5.min.js">&l ...

What is the best way to trigger a localstorage change event using Vue.js?

I'm currently facing an issue with my Vue app related to updating user information stored in localStorage. I've implemented a solution using websockets in App.vue within the mounted function, as shown below: window.Echo.channel("user." ...

The image located at 'http://localhost:8080/favicon.ico' was unable to load due to a violation of its content

I am currently developing a JavaScript app called food2fork. I encountered an issue when the AJAX call API promise is fulfilled and the results (recipes) are rendered. However, when I click on one of the recipes, it moves to the next page and displays: ...

Show a checkbox element with a square in the center instead of a tick mark

Is there a way to create a custom checkbox in HTML with a black box in the center, similar to the third checkbox shown in the image below? I've noticed this design in many interfaces, but I haven't been able to find a satisfactory example online ...

The G/L account specified in the SAP B1 Service Layer is invalid and cannot be used

I attempted to generate a fresh Incoming payment utilizing the service layer, but encountered this issue G/L account is not valid [PaymentAccounts.AccountCode][line: 1] Here is my JSON: { "DocType": "rAccount", "DueDate& ...

Button for searching through the Bootstrap navigation bar

I'm currently working on adding a search menu to the navbar in two different designs - one for screens below 767px and another for screens above 767px. Although I have been successful in expanding the search bar, I am facing issues with the correct p ...

Unable to retrieve the total of numbers stored in the text file

Project: Currently, I am engaged in developing a node.js training module which includes tackling various small projects. One of the tasks at hand is to create an application named account.js using Node that allows users to input transactions via the comma ...

combine elements from a different document using a local field as a key

I'm currently working on a project involving a competition document with a field teams array of objects containing the _id of each team, as well as a score document with a teamId field. The competitions.teams array looks like this: [{_id: 100,..}, {.. ...

The function "onClick" within an external .js file is being referenced

Just starting to learn Javascript and experimenting with an onClick event for an image in an external .js file using the HTML tag. <script type="text/javascript" src="embed.js"> The code found in "embed.js" is as follows: var image1=new Image(); i ...

Utilizing momentjs to convert date and time to various time zones

Within my Angular application, there is a selectbox that allows users to choose the timezone for converting a specific time. I am currently utilizing momentjs for date-time manipulations, however, I am facing an issue regarding changing the timezone of the ...

Handling complex JSON data in KendoUI Grid with varying keys

I have come across a challenging issue with a complex SLC loopback query and the JSON format it returns. Despite my best efforts to find a solution, I seem to be struggling to grasp some of the answers or perhaps I am approaching the problem from the wrong ...

Retrieve data from an external source and display it on my website

Is there a way to extract information from the IEEExplore page using Jquery or Javascript? Can the data be retrieved in JSON format for display on another webpage? I am thinking of using something like this: $.get(url,function( data ) { alert( "Dat ...

Using the active class feature in React Router

Hey there! I've been working with react router v6 and using NavLink to move between components. I've been trying to figure out how to add a custom active class in NavLink, but the method I tried isn't working. Here is what I attempted: <N ...

Tips for creating a reusable function in React.js?

I have a script that executes on input focus and passes certain values based on a specific logic. I would like to reuse this script for multiple input fields that trigger the focus event. How can I accomplish this? This is my current script: <input ...

Steps to incorporate this jQuery script

After receiving a solution to my problem, I'm struggling with how to actually put it into practice. $(function(){ $.get('file1.php', function(data){ $('#dropdown1').html( data ); }); // when dropdown1 is chang ...

Having trouble with reloading the FirebaseAuth widget in an Angular 8 single page application?

I recently developed an Angular 8 CLI project that integrates with FirebaseUI Auth for email and password login. However, I am facing an issue where the FirebaseUI Auth widget does not appear after the user logs out. Is this a bug in the system or am I ove ...

The query limit issue in Sails JS

I am encountering a 413 (Request Entity too large) error when making a request to a Sails Js app (v0.12). Despite my attempts to raise the request limit in the bodyParser, I have not seen any changes take effect. In config/http.js, I included a customize ...

Exploring nested JSON objects within an array using ngFor directive

My application uses Angular 6 and Firebase. I am trying to showcase a list of all appointments. Below is my approach: service.ts getRDV() { this.rdvList = this.firebase.list('/rdv'); return this.rdvList; } Model: export class RDV { key: ...

The issue arises in React Hook useEffect when there is a missing dependency because the dependency is derived from another hook

Currently, I am in the process of developing a web application that retrieves data from an external source. const { data, count, error, isLoading, setEnabled: fetchData } = useData(); useEffect(() => { fetchData(true); }, []); const useData = () ...