Angular HTTP GET mit TypeScript-Fehler http.get (…) .map ist keine Funktion in [null]

334

Ich habe ein Problem mit HTTP in Angular.

Ich möchte nur GETeine JSONListe erstellen und in der Ansicht anzeigen.

Serviceklasse

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());
    }
}

Und in der HallListComponentrufe ich die getHallsMethode aus dem Dienst auf:

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;
        });
    }
}

Ich habe jedoch eine Ausnahme:

TypeError: this.http.get (...). Map ist keine Funktion 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"
  ]
}
Claudiu
quelle
Gibt http.get kein Versprechen zurück?
Bmm6o
1
@ bmm6o Der neue HttpDienst gibt eine beobachtbare zurück
Brocco
1
Ich bin auf ein nahezu identisches Problem gestoßen und habe versucht, ein Projekt von Angular2 Beta-17 auf die endgültige Version zu migrieren. Das Problem für mich war jedoch meine IDE mit VS 2015, Update 3. Die TypeScript-Sprachdiensterweiterung befand sich noch in 1.8.36der ng2-Kurzanleitung (während ich dies schreibe) "typescript": "^2.0.2". Aktualisieren der TS-Sprache. Service über Erweiterungen und Updates hat den Trick für mich getan. Während dieses Updates installiert wurde, stieß ich auf diese SO-Antwort , die mit der gleichen Schlussfolgerung endet.
Eric Lease
Für phpstorm / webstorm löste das Aktualisieren der Typoskriptversion mit der Bibliothek meines Projekts ebenfalls das Problem. Ich folgte den Schritten dieser SO-Antwort: stackoverflow.com/a/31608934/1291428
Sebas

Antworten:

538

Ich denke, dass Sie dies importieren müssen:

import 'rxjs/add/operator/map'

Oder allgemeiner, wenn Sie mehr Methoden für Observable haben möchten. WARNUNG: Dadurch werden alle über 50 Operatoren importiert und Ihrer Anwendung hinzugefügt. Dies wirkt sich auf Ihre Bundle-Größe und Ladezeiten aus.

import 'rxjs/Rx';

Weitere Informationen finden Sie in dieser Ausgabe .

Thierry Templier
quelle
1
Welche Fehler bleiben noch? Sie können diesbezüglich einige spezifische Fragen zu stackoverflow stellen ;-) Diese Frage könnte Ihnen vielleicht auch helfen: stackoverflow.com/questions/34450131/… .
Thierry Templier
1
Ab Angular 2 RC 0 ist dies nicht mehr erforderlich.
Onur Yıldırım
3
@ OnurYıldırım, mit rc.4 ist dieser Import weiterhin erforderlich, es sei denn, ich mache etwas falsch.
Joseph Gabriel
18
Bitte verwenden Sie nicht 'import' rxjs / Rx ';' weil es alles importiert und rxjs dazu neigt, ziemlich groß zu sein. Importieren Sie die Operatoren nach Bedarf.
Drag0
1
Winkel 2 mit rxjs: 5.0.0-beta.12 hier. Und ich musste immer noch import 'rxjs/add/operator/do'... Während wir das nicht mehr tun müssen .map(). Dies half meinem .do()Fall jedoch zu erkennen, dass ich ihn speziell importieren muss. Vielen Dank! Eine Stimme von mir :)
MrCroft
82

Nur ein paar Hintergrundinformationen ... Der neu geprägte Entwicklerleitfaden für Serverkommunikation diskutiert (erwähnt) / erklärt dies:

Die RxJS-Bibliothek ist ziemlich groß. Die Größe spielt eine Rolle, wenn wir eine Produktionsanwendung erstellen und auf mobilen Geräten bereitstellen. Wir sollten nur die Funktionen einbeziehen, die wir tatsächlich benötigen.

Dementsprechend setzt Angular eine abgespeckte Version von Observableim rxjs/ObservableModul, eine Version , die fast alle Betreiber , einschließlich denen , die fehlen würden wir hier wie die Verwendung gerne mapMethode.

Es liegt an uns, die Operatoren hinzuzufügen, die wir benötigen. Wir konnten jeden Operator einzeln hinzufügen, bis wir eine benutzerdefinierte Observable-Implementierung hatten, die genau auf unsere Anforderungen abgestimmt war.

Da @Thierry bereits geantwortet hat, können wir einfach die Operatoren einbeziehen, die wir benötigen:

import 'rxjs/add/operator/map';
import 'rxjs/operator/delay';
import 'rxjs/operator/mergeMap';
import 'rxjs/operator/switchMap';

Wenn wir faul sind, können wir auch alle Operatoren einbeziehen. WARNUNG: Dadurch werden alle über 50 Operatoren zu Ihrem App-Bundle hinzugefügt und die Ladezeiten beeinflusst

import 'rxjs/Rx';
Mark Rajcok
quelle
2
'rxjs / Rx' importieren; Beeindruckend. und alle meine Haare ziehen sofort weg. Ich kann nicht glauben, dass dies für Rxjs / Angular2 nicht auf der ganzen Welt gedruckt wird. Vielen Dank!!!
JimB
Aber es wird häufig nicht fusseln, standardmäßig ist es ein Import auf der schwarzen Liste. Erstellen Sie ein neues eckiges CLI-Projekt. Ich liebe die Bequemlichkeit selbst, aber die Konvention an den Orten, an denen ich in NYC arbeite, ist es nicht, es zu tun.
Tim Consolazio
21

Ab rxjs 5.5 können Sie die pipeable Operatoren verwenden

import { map } from 'rxjs/operators';

Was ist los mit dem import 'rxjs/add/operator/map';

Wenn wir diesen Ansatz verwenden map, wird der Operator auf observable.prototype dieses Objekt gepatcht und wird Teil dieses Objekts.

Wenn Sie später entscheiden, den mapOperator aus dem Code zu entfernen, der den beobachtbaren Stream verarbeitet, die entsprechende Importanweisung jedoch nicht entfernen, mapbleibt der implementierte Code ein Teil von Observable.prototype.

Wenn die Bundler versuchen, den nicht verwendeten Code (auch bekannt als tree shaking ) zu entfernen , entscheiden sie sich möglicherweise dafür, den Code des mapOperators im Observable zu behalten , obwohl er nicht in der Anwendung verwendet wird.

Lösung -Pipeable operators

Pipeable- Operatoren sind reine Funktionen und patchen das Observable nicht . Sie können Operatoren mithilfe der ES6-Importsyntax importieren import { map } from "rxjs/operators"und sie dann in eine Funktion pipe()einschließen, die eine variable Anzahl von Parametern akzeptiert, dh verkettbare Operatoren.

Etwas wie das:

getHalls() {
    return this.http.get(HallService.PATH + 'hall.json')
    .pipe(
        map((res: Response) => res.json())
    );
}
Sachila Ranawaka
quelle
16

Mit Angular 5 wird der RxJS-Import verbessert.

Anstatt

import 'rxjs/add/operator/map';

Wir können jetzt

import { map } from 'rxjs/operators';
Claudiu
quelle
Wenn Sie diesen Ansatz verwenden, enthält er jetzt in Ihrem Build nur verwendete Operatoren (in diesem Fall map). Früher wurden alle Operatoren aus der rxjs-Bibliothek eingeschlossen. Weitere Informationen finden Sie unter dem folgenden Link. loiane.com/2017/08/angular-rxjs-imports
Hiren Shah
13

Die Observable.subscribedirekte Verwendung sollte funktionieren.

@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()); // <<--
    }
}
TheKojuEffect
quelle
5
Dies ist kein sehr effizienter Ansatz. Wenn beispielsweise mehrere Abonnenten vorhanden sind, müssen diese jeweils eine Karte für die Daten ausführen, anstatt sie nur einmal im Dienst auszuführen. Ich denke, OP hatte den richtigen Ansatz, hatte einfach nicht das richtige Modul geladen, um es zu verwenden.
Evan Plaice
3

Für Angular-Versionen 5 und höher sieht die aktualisierte Importzeile folgendermaßen aus:

import { map } from 'rxjs/operators';

ODER

import { map } from 'rxjs/operators';

Auch diese Versionen unterstützen Pipable Operators vollständig, sodass Sie .pipe () und .subscribe () problemlos verwenden können.

Wenn Sie Angular Version 2 verwenden, sollte die folgende Zeile absolut einwandfrei funktionieren:

import 'rxjs/add/operator/map';

ODER

import 'rxjs/add/operators/map';

Wenn Sie immer noch auf ein Problem stoßen, müssen Sie Folgendes tun:

import 'rxjs/Rx';

Ich würde es nicht vorziehen, wenn Sie es direkt verwenden, da es die Ladezeit verlängert, da es eine große Anzahl von Operatoren enthält (nützliche und nicht nützliche), was gemäß den Industrienormen keine gute Praxis ist. Stellen Sie also sicher Sie versuchen zuerst, die oben genannten Importzeilen zu verwenden. Wenn dies nicht funktioniert, sollten Sie sich für rxjs / Rx entscheiden

Jitendra Ahuja
quelle
3

Ich habe eine Lösung für dieses Problem

Installieren Sie dieses Paket:

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

Importieren Sie dann diese Bibliothek

import 'rxjs/add/operator/map'

Starten Sie dann endlich Ihr ionisches Projekt neu

ionic serve -l
divyajeet singh
quelle
3

Angular Version 6 "0.6.8" rxjs Version 6 "^ 6.0.0"

Diese Lösung ist für:

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

Wie wir alle wissen, wird Angular jeden Tag entwickelt, daher gibt es jeden Tag viele Änderungen. Diese Lösung ist für Angular 6 und RXJS 6 gedacht, die
zuerst mit http arbeiten. Sie sollten es importieren von: Schließlich müssen Sie das HttpModule in der App deklarieren. module.ts

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

und Sie müssen HttpModule zu Ngmodule hinzufügen -> Importe

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

Um mit der Karte zu arbeiten, sollten Sie zuerst die Pipe importieren:

import { pipe } from 'rxjs';

Drittens benötigen Sie den Kartenfunktionsimport von:

import { map } from 'rxjs/operators';

Sie müssen die Karte in der Pipe wie folgt verwenden:

 constructor(public http:Http){  }

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

das funktioniert vollkommen viel glück!

Nadir Hamidou
quelle
2

Die Karte, die Sie hier verwenden, ist nicht .map()in Javascript, sondern die Rxjs-Kartenfunktion, an der gearbeitet wirdObservables in Angular ...

In diesem Fall müssen Sie es importieren, wenn Sie eine Karte für die Ergebnisdaten verwenden möchten ...

map(project: function(value: T, index: number): R, thisArg: any): Observable<R> Wendet eine bestimmte Projektfunktion auf jeden von der Quelle Observable ausgegebenen Wert an und gibt die resultierenden Werte als Observable aus.

Importieren Sie es einfach so:

import 'rxjs/add/operator/map';
Alireza
quelle
1

Da Http - Service in angular2 kehrt einen Observable - Typen, von Ihrem Angular2 Installationsverzeichnis ( ‚node_modules‘ in meinem Fall), müssen wir importieren Kartenfunktion der beobachtbaren in Ihrer Komponente mit http - Service, wie:

import 'rxjs/add/operator/map';
Amardeep Kohli
quelle
1

Winkel 6 - nur der Import von 'rxjs / Rx' hat den Trick für mich gemacht

Shimi Avizmil
quelle
1

Fügen Sie einfach die Zeile in Ihre Datei ein,

'rxjs / Rx' importieren;

Es werden eine Reihe von Abhängigkeiten importiert. In Winkel 5 getestet

Mandeep Singh
quelle
0

RxJs hat seinen Kartenoperator zwar in einem separaten Modul getrennt, und jetzt müssen Sie ihn wie jeden anderen Operator explizit importieren.

import rxjs/add/operator/map;

und es wird dir gut gehen.

Piyush Patel
quelle
0

Der globale Import ist sicher.

'rxjs / Rx' importieren;

Rut Shah
quelle
0
import 'rxjs/add/operator/map';

wird Ihr Problem lösen

Ich habe es in Angular 5.2.0 und RXJS 5.5.2 getestet

Mayank Bhardwaj
quelle
0

Dies geschieht, weil Sie die rxjs verwenden und die Funktion in rxjs nicht statisch ist. Dies bedeutet, dass Sie sie nicht direkt aufrufen können. Sie müssen die Methoden in der Pipe aufrufen und diese Funktion aus der rxjs-Bibliothek importieren

Wenn Sie jedoch rxjs-kompatibel verwenden, müssen Sie nur die rxjs-kompatiblen Operatoren importieren

Gurvinder Guraya
quelle
0

Ich habe die folgenden Befehle ausprobiert und es wird behoben:

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


import 'rxjs/Rx';
Phan Hero
quelle
Dies dient nur dazu, dass Sie zunächst in rxjs 6 arbeiten, indem Sie einige Patches für Sie durchführen. Es ist nur eine kurzfristige Lösung und der vollständige Übergang von rxjs 6 sollte erfolgen.
HankCa
0

{map} aus 'rxjs / operator' importieren;

Das funktioniert bei mir in Winkel 8

user2900572
quelle
0

Und was @ mlc-mlapis kommentiert hat, Sie mischen vermietbare Operatoren und die Patch-Methode für Prototypen. Verwenden Sie den einen oder anderen .

Für Ihren Fall sollte es sein

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

Yogesh Waghmare
quelle