0

When I call the map() function on a parsed JSON object (in the mapStocks() function as shown below), it fails if I place the toStock() function inside the StockService class. However, if I declare the function as a "global" function outside the StockService class, it doesn't throw an error.

import { Injectable } from '@angular/core';
import { Http, Headers, Response } from '@angular/http';
//import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';

import { Stock } from './stock';

@Injectable()
export class StockService {
    private baseUrl: string = 'https://www.vendor-api-website.com';

    constructor(private http: Http) {
    }

    getStocks(): Promise<Stock[]> {
        console.log('Loading stocks...');

        let stocks$ = this.http
        .get(`${this.baseUrl}/api/getInventory`, { headers: this.getHeaders() })
        .map(this.mapStocks)
        .toPromise()
        .catch(this.handleError);

        return stocks$;
    }

    private getHeaders() {
        let headers = new Headers();
        headers.append('Accept', 'application/json');
        return headers;
    }

    private handleError(error: any): Promise<any> {
        //console.error('An error occurred', error); // for demo purposes only
        return Promise.reject(error.message || error);
    }

    private mapStocks(response:Response): Stock[] {
        console.log('Mapping inventory...');
        // this fails...
        return response.json().map(this.toStock);
        // ..but this is okay?
        //return response.json() as Stock[];
    }

    // This succeeds if declared as a function and placed outside the class
    private toStock(stockObject:any): Stock {
        console.log('toStock called');

        let stock = <Stock>({
            id: stockObject.id,
            code: stockObject.code,
            name: stockObject.name,
            description: stockObject.description,
            supplier: stockObject.supplier,
            cost: stockObject.unitPrice * stockObject.minQuantity,
            quantity: stockObject.minQuantity
        });

        console.log('Parsed stock:', stock);

        return stock;
    }
}

As you can see, we need the toStock() function in order to do some calculations before assigning it to our own array of Stock objects.

The error that is thrown if I declare the toStock() function in the StockService class is this: enter image description here Could anyone please explain why this is so? Is it a limitation of TypeScript?

StrangeCode
  • 193
  • 1
  • 10
  • 2
    See my answer to this question to understand how `this` work in javascript: http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal/13441628?s=1|4.1256#13441628 – slebetman Mar 24 '17 at 07:15
  • @StrangeCode . `this` have different scope on typescript. Thats why we often use `() => //do something` (Arrow Function) since when u enter the `function () { this here is different than this outside this scope}` – Reyan Tropia Mar 24 '17 at 07:57

2 Answers2

4

You are setting a regular javascript function here: .map(this.mapStocks). The this object will change to that of the function instead of the class. Here this.toStock() is undefined.

Use Function.Prototype.bind()

.map(this.mapStocks.bind(this))

Complete call:

 let stocks$ = this.http
    .get(`${this.baseUrl}/api/getInventory`, { headers: this.getHeaders() })
    .map(this.mapStocks.bind(this))
    .toPromise()
    .catch(this.handleError);
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
-2
  getStocks(): Promise<Stock[]> {
console.log('Loading stocks...');
let stocks$ = this.http
  .get(`${this.baseUrl}/api/getInventory`, { headers: this.getHeaders() })
  .map(res => { return this.toStock(res.json()) })
  .catch(this.handleError);
}
Prateik
  • 241
  • 2
  • 6
  • 14