Fridez Lucas
Fridez Lucas

Reputation: 33

Angular2 Http get request with service

I can't use my function (in a service) for an http get request but if I use my function in my component directly, it works. I use a PHP file that returns return a JSON.

I receive this error

"Uncaught (in promise): TypeError: Cannot set property stack of [object Object] which has only a getter
TypeError: Cannot set property stack of [object Object] which has only a getter
at assignAll (http://localhost:4200/vendor.bundle.js:112997:29)
at ViewWrappedError.ZoneAwareError (http://localhost:4200/vendor.bundle.js:113068:16)
at ViewWrappedError.BaseError [as constructor] (http://localhost:4200/vendor.bundle.js:6624:16)
at ViewWrappedError.WrappedError [as constructor] (http://localhost:4200/vendor.bundle.js:6686:16)
at new ViewWrappedError (http://localhost:4200/vendor.bundle.js:63377:16)
at CompiledTemplate.proxyViewClass.DebugAppView._rethrowWithContext (http://localhost:4200/vendor.bundle.js:90236:23)
at CompiledTemplate.proxyViewClass.DebugAppView.detectChanges (http://localhost:4200/vendor.bundle.js:90209:18)
at ViewRef_.detectChanges (http://localhost:4200/vendor.bundle.js:64323:20)
at RouterOutlet.activate (http://localhost:4200/vendor.bundle.js:74734:42)
at ActivateRoutes.placeComponentIntoOutlet (http://localhost:4200/vendor.bundle.js:25777:16)
at ActivateRoutes.activateRoutes (http://localhost:4200/vendor.bundle.js:25744:26)
at http://localhost:4200/vendor.bundle.js:25680:58
at Array.forEach (native)
at ActivateRoutes.activateChildRoutes (http://localhost:4200/vendor.bundle.js:25680:29)
at ActivateRoutes.activate (http://localhost:4200/vendor.bundle.js:25654:14)"

It doesn't work

Component

import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {Shoe} from './shoe';
import {FileService} from  './../services/file.service';
import {ShoeService} from  './../services/shoe.service';
import {Observable} from "rxjs";

@Component({
    selector: 'shoe',
    templateUrl: 'shoe-detail.component.html',
    providers: [FileService]
})
export class ShoeDetailComponent implements OnInit {

constructor(private shoeService: ShoeService) {}

data : any;

ngOnInit() {
        this.data = this.shoeService.getData();
    });
}

Service

import { Injectable } from '@angular/core';
import { Shoe } from './../shoe/shoe';
import {Http, Response} from '@angular/http';

@Injectable()
export class ShoeService {

constructor (private http: Http) {}

getData() {
    return this.http.get('http://.../test.php')
        .subscribe(data => data.json());
    }
}

PHP

<?php
header("Access-Control-Allow-Origin: *");
$data = array(
    array('id' => '1','first_name' => 'Cynthia'),
    array('id' => '2','first_name' => 'Keith'),
    array('id' => '3','first_name' => 'Robert'),
    array('id' => '4','first_name' => 'Theresa'),
    array('id' => '5','first_name' => 'Margaret')
);

echo json_encode($data);
?>

It works

import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {Shoe} from './shoe';
import {FileService} from  './../services/file.service';
import {ShoeService} from  './../services/shoe.service';
import {Http, Response} from '@angular/http';

@Component({
    selector: 'shoe',
    templateUrl: 'shoe-detail.component.html',
    providers: [FileService]
})
export class ShoeDetailComponent implements OnInit {

constructor(private fileService: FileService,
            private shoeService: ShoeService,
            private route: ActivatedRoute,
            private http: Http) {
}

data: any;

ngOnInit() {
    this.http.get('http://...test.php')
            .subscribe(data => this.data = data.json());
    });
}
}

Upvotes: 2

Views: 6131

Answers (2)

Aravind
Aravind

Reputation: 41533

You should map to data using a response object as below

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

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
@Injectable()

export class ShoeService {
    constructor(private _http: Http) {
    }
    getData(): Observable<any[]> {
        return this._http.get('http://......')
            .map((response: Response) => <any[]>response.json())
            .do(data => console.log("data we got is " + JSON.stringify(data)))
                .catch(this.handleError);

    }
    private handleError(error: Response) {
            console.log(error);
            return Observable.throw(error.json().error || 'Internal Server error');
    }
}

and your ngOnInit should be as

ngOnInit() : void{
        this._taskService.getData()
                    .subscribe(data => this.data = data,
                    error =>this.errorMessage =<any> error)
    } 

Also, modify the type of your data in your ShoeDetailComponent as

data : any[]

Upvotes: 1

Igor
Igor

Reputation: 62213

In your component you are calling the service which returns an Observable but you assign that Observable directly to your data instead of subscribing to its results.

It should be

ngOnInit() {
    this.shoeService.getData().subscribe(data => this.data = data);
});

And in your service you should call map instead of subscribe so you return the data and not the HttpResult.

getData(): Observable<any> {
    return this.http.get('http://.../test.php')
        .map(data => data.json());
    }
}

Note that in order to provide better type support you should define what it is your methods return. Example: getData(): Observable<any> and even better would be if you replace any with an interface type you define or collection/array of interface if it is a collection.

Example

export interface IUser {id: number; first_name: string}

Service method

getData(): Observable<IUser[]> {
    return this.http.get('http://.../test.php')
        .Map(data => data.json() as IUser[]);
    }
}

Upvotes: 5

Related Questions