348

I have a problem with HTTP in Angular.

I just want to GET a JSON list and show it in the view.

Service class

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]

hall-center.component

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{}

app.component

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 { }

tsconfig.json

{
  "compilerOptions": {
    "target": "ES5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules"
  ]
}
4
  • Doesn't http.get return a promise?
    – bmm6o
    Commented Dec 29, 2015 at 16:38
  • 2
    @bmm6o The new Http service returns an observable
    – Brocco
    Commented Dec 29, 2015 at 16:39
  • 2
    I ran into a nearly identical issue, trying to migrate a project from Angular2 beta-17 to final release. The issue for me was my IDE though, using VS 2015, Update 3. The TypeScript language service extension was still at 1.8.36, whereas as the ng2 quickstart guide (as I write this) is using "typescript": "^2.0.2". Upgrading the TS lang. service via Extensions and Updates did the trick for me. While that update was being installed I came across this SO answer, which ends with the same conclusion.
    – Eric Lease
    Commented Sep 21, 2016 at 7:03
  • For phpstorm/webstorm, updating the typescript version with the library of my project also solved the problem. I followed the steps of this SO answer: stackoverflow.com/a/31608934/1291428
    – Sebas
    Commented Dec 11, 2016 at 15:20

19 Answers 19

541

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.

9
  • 3
    Which errors still remain? You can ask some specific questions regarding this on stackoverflow ;-) This question could perhaps help you as well: stackoverflow.com/questions/34450131/…. Commented Jan 10, 2016 at 8:55
  • 2
    As of Angular 2 RC 0, this is no longer required. Commented Jul 30, 2016 at 12:17
  • 4
    @OnurYıldırım, using rc.4, this import is still required, unless I'm doing something wrong. Commented Aug 3, 2016 at 2:37
  • 18
    Please don't use 'import 'rxjs/Rx';' because it imports everything and rxjs tends to be pretty big. Import operators one by one as you need them.
    – Drag0
    Commented Sep 22, 2016 at 13:56
  • 2
    Angular 2 with rxjs: 5.0.0-beta.12 here. And I still had to import 'rxjs/add/operator/do'... While we don't have to do this for .map() anymore. But this helped my .do() case, to realize I specifically need to import it. Thank you! One up vote from me :)
    – MrCroft
    Commented Sep 25, 2016 at 17:56
84

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 the rxjs/Observable module, a version that lacks almost all operators including the ones we'd like to use here such as the map 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';
2
  • 2
    import 'rxjs/Rx'; wow. and all my hair pulling instantly goes away. i can't believe this isn't printed all over the world for Rxjs/Angular2. thanks!!!
    – JimB
    Commented Mar 23, 2016 at 16:59
  • But it frequently won't lint, by default it's a blacklisted import. Create a new angular CLI project, you'll see. I love the convenience myself but the convention in the places I work in NYC is not to do it. Commented Apr 20, 2018 at 13:54
24

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())
    );
}
1
  • Yeah, now currently with Rxjs version 7+, it's recommended to use pipeable operators by using pipe, nice one, I found all the previous answers old and not updated with the current versions of Angular and Rxjs Commented Jul 13, 2021 at 23:03
17

With Angular 5 the RxJS import is improved.

Instead of

import 'rxjs/add/operator/map';

We can now

import { map } from 'rxjs/operators';
1
  • Using this approach,now in your build it will only include used operators ( map in this case), earlier it was including all the operators from rxjs library. check below link for more detail. loiane.com/2017/08/angular-rxjs-imports
    – Hiren Shah
    Commented Jun 15, 2018 at 5:44
15

Using Observable.subscribe directly should work.

@Injectable()
export class HallService {
    public http:Http;
    public static PATH:string = 'app/backend/'    

    constructor(http:Http) {
        this.http=http;
    }

    getHalls() {
    // ########### No map
           return this.http.get(HallService.PATH + 'hall.json');
    }
}


export class HallListComponent implements OnInit {
    public halls:Hall[];
    / *** /
    ngOnInit() {
        this._service.getHalls()
           .subscribe(halls => this.halls = halls.json()); // <<--
    }
}
1
  • 6
    This isn't a very efficient approach. For instance if there are multiple subscribers they will each have to run map on the data, rather than just doing it once in the service. I think OP had the right approach, just didn't have the right module loaded to use it. Commented Jan 25, 2016 at 18:17
5

For Angular versions 5 and above, the updated importing line looks like :

import { map } from 'rxjs/operators';

OR

import { map } from 'rxjs/operators';

Also these versions totally supports Pipable Operators so you can easily use .pipe() and .subscribe().

If you are using Angular version 2, then the following line should work absolutely fine :

import 'rxjs/add/operator/map';

OR

import 'rxjs/add/operators/map';

If you still encounter a problem then you must go with :

import 'rxjs/Rx';

I won't prefer you to use it directly bcoz it boosts the Load time, as it has a large number of operators in it (useful and un-useful ones) which is not a good practice according to the industry norms, so make sure you try using the above mentioned importing lines first, and if that not works then you should go for rxjs/Rx

4

I have a solution of this problem

Install this package:

npm install rxjs@6 rxjs-compat@6 --save

then import this library

import 'rxjs/add/operator/map'

finally restart your ionic project then

ionic serve -l
4

The map you using here is not the .map() in JavaScript, it's Rxjs map function which working on Observables in Angular.

So in that case you need to import it if you'd like to use map on the result data.

map(project: function(value: T, index: number): R, thisArg: any): Observable<R> Applies a given project function to each value emitted by the source Observable, and emits the resulting values as an Observable.

So simply import it like this:

import 'rxjs/add/operator/map';
3

Angular version 6 "0.6.8" rxjs version 6 "^6.0.0"

this solution is for :

  "@angular-devkit/core": "0.6.8",
  "rxjs": "^6.0.0"

as we all know angular is being developed every day so there are lots of changes every day and this solution is for angular 6 and rxjs 6
first to work with http yo should import it from : after all you have to declare the HttpModule in app.module.ts

import { Http } from '@angular/http';

and you have to add HttpModule to Ngmodule -> imports

  imports: [
    HttpModule,
    BrowserModule,
    FormsModule,
    RouterModule.forRoot(appRoutes)
  ],

second to work with map you should first import pipe :

import { pipe } from 'rxjs';

third you need the map function import from :

import { map } from 'rxjs/operators';

you have to use map inside pipe like this exemple :

 constructor(public http:Http){  }

    getusersGET(){
        return this.http.get('http://jsonplaceholder.typicode.com/users').pipe(
         map(res => res.json()  )  );
    }

that works perfectly good luck !

2

Since Http service in angular2 returns an Observable type, From your Angular2 installation directory('node_modules' in my case),We need to import map function of the Observable in your component using http service,as:

import 'rxjs/add/operator/map';
2

Angular 6 - only import 'rxjs/Rx' did the trick for me

1

Just add the line in your file,

import 'rxjs/Rx';

It will import bunch of dependencies. Tested in angular 5

0
0

True, RxJs has separated its map operator in a separate module and now you need to explicity import it like any other operator.

import rxjs/add/operator/map;

and you will be fine.

0

Global import is safe to go with.

import 'rxjs/Rx';

0
import 'rxjs/add/operator/map';

will resolve your problem

I tested it in angular 5.2.0 and rxjs 5.5.2

0

this is happening because you are using the rxjs and in rxjs function are not static which means you can't call them directly you have to call the methods inside the pipe and import that function from the rxjs library

But if you are using rxjs-compat then you just need to import the rxjs-compat operators

0

I tried below commands and it gets fixed:

npm install rxjs@6 rxjs-compat@6 --save


import 'rxjs/Rx';
1
  • That is only to get you initially working in rxjs 6 by performing some patching for you. It is only a short-term fix and the full rxjs 6 transition should be made.
    – HankCa
    Commented Jun 25, 2019 at 0:43
0

import { map } from 'rxjs/operators';

this works for me in angular 8

0

Plus what @mlc-mlapis commented, you're mixing lettable operators and the prototype patching method. Use one or the other.

For your case it should be

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map';

@Injectable()
export class SwPeopleService {
    people$ = this.http.get('https://swapi.co/api/people/')
      .map((res:any) => res.results);

    constructor(private http: HttpClient) {} 
}

https://stackblitz.com/edit/angular-http-observables-9nchvz?file=app%2Fsw-people.service.ts

Not the answer you're looking for? Browse other questions tagged or ask your own question.