Reputation: 33
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
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
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