Werner Swart Werner Swart - 3 months ago 15
HTTP Question

Angular 2 private variables disappear

I have the following code which is a simple service that goes back to the server to fetch some data:

import { Injectable } from '@angular/core';
import { Action } from '../shared';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Authenticated } from '../authenticated';
import 'rxjs/Rx';

@Injectable()
export class ActionsService {
private url = 'http://localhost/api/actions';
constructor(private http: Http, private authenticated : Authenticated) {}

getActions(search:string): Observable<Action[]> {
let options = this.getOptions(false);

let queryString = `?page=1&size=10&search=${search}`;
return this.http.get(`${this.url + queryString}`, options)
.map(this.extractData)
.catch(this.handleError);
}

private extractData(response: Response) {
let body = response.json();
return body || { };
}

private handleError (error: any) {
let errMsg = (error.message) ? error.message : error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg); // log to console instead

if (error.status == 403) {
this.authenticated.logout();
}

return Observable.throw(errMsg);
}

private getOptions(addContentType: boolean) : RequestOptions {
let headers = new Headers();
if (addContentType) {
headers.append('Content-Type', 'application/json');
}

let authToken = JSON.parse(localStorage.getItem('auth_token'));
headers.append('Authorization', `Bearer ${authToken.access_token}`);

return new RequestOptions({ headers: headers });
}
}


Everything works as expected except for handleError. As soon as getActions receives an error from the server it goes into the this.handleError method which again works fine up until the section where this.authenticated.logout() should be called. this.autenticated is undefined and I am not sure if it is because "this" is referring to another object or if ActionSerivce's local variables are made null when and http exception occurs. The authenticated local variable is properly injected (I did a console.log in the constructor and it was there).

Answer

The problem is that you are not binding the this context in your callback function. You should declare your http call like this for example:

return this.http.get(`${this.url + queryString}`, options)
                .map(this.extractData.bind(this))    //bind
                .catch(this.handleError.bind(this)); //bind

Another option could be to pass an anonymous function and call the callback from there:

return this.http.get(`${this.url + queryString}`, options)
                .map((result) => { return this.extractData(result)})
                .catch((result) => { return this.handleError(result}));

And yet another option is to declare your callback functions a little differently, you can keep your http call the way you had it before:

private extractData: Function = (response: Response): any => {
    let body = response.json();
    return body || { };
}

private handleError: Function = (error: any): any => {    
    //...
}