9

I'm new to Angular 2 and Observables so I apologise if my problem is trivial. Anyway I'm trying to test the Angular 2 HTTP Client using RxJS. Although I got it to work I need to add more logic to the service I'm currently working on. Basically I'd like to have a mapping function to convert the object I receive from the web service I'm connected to, to the model object I have in Angular.

This is the code that works:

import { Injectable } from 'angular2/core';
import { Http, Response } from 'angular2/http';
import { Observable } from 'rxjs/Observable';

import { Person } from '../models/person';

@Injectable()
export class PersonsService {

    constructor(private http: Http) { }

    private personsUrl = 'http://localhost/api/persons';

    getPersons(): Observable<Person[]> {
        return this.http.get(this.personsUrl)
            .map(this.extractData)
            .catch(this.handleError);
    }

    private extractData(res: Response) {
        if(res.status < 200 || res.status >= 300) {
            throw new Error('Bad response status ' + res.status);
        }

        let body = res.json();
        return body.data || {};
    }

    private handleError(error: any) {
        let errMsg = error.message;
        return Observable.throw(errMsg);
    }
}

With the above code I have no problems whatsoever. The issue I'm having is that I'd like to map the object I'm getting from the service to the one I have in Angular i.e. Person. What I tried is to call another function from the extractData function that's being used by the .map function.

private extractData(res: Response) {
    if(res.status < 200 || res.status >= 300) {
        throw new Error('Bad response status ' + res.status);
    }

    let body = res.json();
    // map data function
    var data = this.mapData(body.data);

    return data || {};
}

private mapData(data: any) {
    // code to map data
}

Obviously the code above doesn't work as when this is referenced inside the extractData function, this does not refer to the PersonsService class, but it refers to a MapSubscriber object.

I don't know if it is possible to call an "external" function. It might be a silly thing but I can't find any information regarding this.

2 Answers 2

23

Instead of just passing the function reference use arrow functions to retain this

.map((res) => this.extractData(res))
Sign up to request clarification or add additional context in comments.

4 Comments

Perfect! Thanks a lot :) Could you explain the reasoning behind it please?
developer.mozilla.org/en/docs/Web/JavaScript/Reference/… without it this will point to the function where the call is made.
passing this reference as second param to map(fn,this) function will also do the same thing with less verbosity,refer my answer
Interesting, didn't know. .map(this.extractData.bind(this)) would also work. I prefer arrow functions everywhere though. Consistency makes it easier to avoid mistakes.
4

Observable's map function allows you to pass a reference variable as a second argument on how should this actually work inside the higher-order function.
so the solution is
.map(this.extractData,this)
This way while passing the extractData function you are also passing the current class's this execution context to the higher-order function. It will work.

Observable Doc Reference Link

screenshot of the doc

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.