I have a problem with HTTP in Angular.
I just want to GET
a JSON
list and show it in the view.
import {Injectable} from "angular2/core";
import {Hall} from "./hall";
import {Http} from "angular2/http";
@Injectable()
export class HallService {
public http:Http;
public static PATH:string = 'app/backend/'
constructor(http:Http) {
this.http=http;
}
getHalls() {
return this.http.get(HallService.PATH + 'hall.json').map((res:Response) => res.json());
}
}
And in the HallListComponent
I call the getHalls
method from the service:
export class HallListComponent implements OnInit {
public halls:Hall[];
public _selectedId:number;
constructor(private _router:Router,
private _routeParams:RouteParams,
private _service:HallService) {
this._selectedId = +_routeParams.get('id');
}
ngOnInit() {
this._service.getHalls().subscribe((halls:Hall[])=>{
this.halls=halls;
});
}
}
However, I got an exception:
TypeError: this.http.get(...).map is not a function in [null]
import {Component} from "angular2/core";
import {RouterOutlet} from "angular2/router";
import {HallService} from "./hall.service";
import {RouteConfig} from "angular2/router";
import {HallListComponent} from "./hall-list.component";
import {HallDetailComponent} from "./hall-detail.component";
@Component({
template:`
<h2>my app</h2>
<router-outlet></router-outlet>
`,
directives: [RouterOutlet],
providers: [HallService]
})
@RouteConfig([
{path: '/', name: 'HallCenter', component:HallListComponent, useAsDefault:true},
{path: '/hall-list', name: 'HallList', component:HallListComponent}
])
export class HallCenterComponent{}
import {Component} from 'angular2/core';
import {ROUTER_DIRECTIVES} from "angular2/router";
import {RouteConfig} from "angular2/router";
import {HallCenterComponent} from "./hall/hall-center.component";
@Component({
selector: 'my-app',
template: `
<h1>Examenopdracht Factory</h1>
<a [routerLink]="['HallCenter']">Hall overview</a>
<router-outlet></router-outlet>
`,
directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
{path: '/hall-center/...', name:'HallCenter',component:HallCenterComponent,useAsDefault:true}
])
export class AppComponent { }
{
"compilerOptions": {
"target": "ES5",
"module": "system",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"exclude": [
"node_modules"
]
}
I think that you need to import this:
import 'rxjs/add/operator/map'
Or more generally this if you want to have more methods for observables. WARNING: This will import all 50+ operators and add them to your application, thus affecting your bundle size and load times.
import 'rxjs/Rx';
See this issue for more details.
Just some background... The newly minted Server Communication dev guide (finally) discusses/mentions/explains this:
The RxJS library is quite large. Size matters when we build a production application and deploy it to mobile devices. We should include only those features that we actually need.
Accordingly, Angular exposes a stripped down version of
Observable
in therxjs/Observable
module, a version that lacks almost all operators including the ones we'd like to use here such as themap
method.It's up to us to add the operators we need. We could add each operator, one-by-one, until we had a custom Observable implementation tuned precisely to our requirements.
So as @Thierry already answered, we can just pull in the operators we need:
import 'rxjs/add/operator/map';
import 'rxjs/operator/delay';
import 'rxjs/operator/mergeMap';
import 'rxjs/operator/switchMap';
Or, if we're lazy we can pull in the full set of operators. WARNING: this will add all 50+ operators to your app bundle, and will effect load times
import 'rxjs/Rx';
From rxjs 5.5 onwards, you can use the pipeable operators
import { map } from 'rxjs/operators';
What is wrong with the import 'rxjs/add/operator/map';
When we use this approach map
operator will be patched to observable.prototype
and becomes a part of this object.
If later on, you decide to remove map
operator from the code that handles the observable stream but fail to remove the corresponding import statement, the code that implements map
remains a part of the Observable.prototype
.
When the bundlers tries to eliminate the unused code (a.k.a. tree shaking
), they may decide to keep the code of the map
operator in the Observable even though it’s not being used in the application.
Solution - Pipeable operators
Pipeable operators are pure functions and do not patch the Observable. You can import operators using the ES6 import syntax import { map } from "rxjs/operators"
and then wrap them into a function pipe()
that takes a variable number of parameters, i.e. chainable operators.
Something like this:
getHalls() {
return this.http.get(HallService.PATH + 'hall.json')
.pipe(
map((res: Response) => res.json())
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With