Kątowy HTTP GET z błędem TypeScript http.get (…) .map nie jest funkcją w [null]


334

Mam problem z HTTP w Angular.

Chcę tylko GETz JSONlisty i wyświetlić je w widoku.

Klasa usług

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

I w HallListComponentwywołuję getHallsmetodę z usługi:

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

Mam jednak wyjątek:

TypeError: this.http.get (...). Mapa nie jest funkcją w [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"
  ]
}

Czy http.get nie zwraca obietnicy?
bmm6o,

1
@ bmm6o Nowa Httpusługa zwraca obserwowalny
Brocco

1
Natknąłem się na prawie identyczny problem, próbując migrować projekt z Angular2 beta-17 do ostatecznej wersji. Problemem było jednak moje IDE, przy użyciu VS 2015, aktualizacja 3. Rozszerzenie usługi językowej TypeScript wciąż było dostępne 1.8.36, podczas gdy jako przewodnik szybkiego startu ng2 (jak to piszę) używa "typescript": "^2.0.2". Aktualizacja języka TS. obsługa za pośrednictwem rozszerzeń i aktualizacji załatwiła sprawę. Podczas instalacji tej aktualizacji natknąłem się na odpowiedź SO , która kończy się tym samym wnioskiem.
Eric Lease

W przypadku phpstorm / webstorm, aktualizacja wersji maszynopisu z biblioteką mojego projektu również rozwiązała problem. Postępowałem zgodnie z krokami tej SO odpowiedzi: stackoverflow.com/a/31608934/1291428
Sebas

Odpowiedzi:


538

Myślę, że musisz to zaimportować:

import 'rxjs/add/operator/map'

Lub bardziej ogólnie, jeśli chcesz mieć więcej metod obserwowalnych. OSTRZEŻENIE: Spowoduje to zaimportowanie wszystkich ponad 50 operatorów i doda ich do aplikacji, wpływając w ten sposób na rozmiar pakietu i czas ładowania.

import 'rxjs/Rx';

Zobacz ten problem, aby uzyskać więcej informacji.


1
Które błędy nadal pozostają? Można zadać kilka pytań szczegółowych dotyczących tego na stackoverflow ;-) to pytanie być może pomóc także: stackoverflow.com/questions/34450131/... .
Thierry Templier

1
Od Angular 2 RC 0 nie jest to już wymagane.
Onur Yıldırım

3
@ OnurYıldırım, używając rc.4, ten import jest nadal wymagany, chyba że robię coś złego.
Joseph Gabriel,

18
Proszę nie używać 'importuj' rxjs / Rx ';' ponieważ importuje wszystko, a rxjs wydaje się być dość duży. Importuj operatorów jeden po drugim, tak jak potrzebujesz.
Drag0

1
Angular 2 z rxjs: 5.0.0-beta.12 tutaj. I wciąż musiałem import 'rxjs/add/operator/do'... Chociaż nie musimy .map()już tego robić . Ale to pomogło mojej .do()sprawie, aby zdać sobie sprawę, że muszę ją zaimportować. Dziękuję Ci! Jeden głos ode mnie :)
MrCroft 25.09.16

82

Tylko trochę tła ... Nowo opracowany przewodnik deweloperów komunikacji serwera omawia / wspomina / wyjaśnia to:

Biblioteka RxJS jest dość duża. Rozmiar ma znaczenie, gdy budujemy aplikację produkcyjną i wdrażamy ją na urządzenia mobilne. Powinniśmy uwzględnić tylko te funkcje, których faktycznie potrzebujemy.

W związku z powyższym, kątowe naraża uproszczoną wersję Observablew rxjs/Observablemodule wersję, której brakuje prawie wszyscy operatorzy w tym te, które chcielibyśmy wykorzystać tutaj, takich jak mapmetody.

To od nas zależy, czy dodamy operatorów, których potrzebujemy. Możemy dodawać każdego operatora, jeden po drugim, dopóki nie będziemy mieć niestandardowej implementacji Observable dostosowanej dokładnie do naszych wymagań.

Ponieważ @Thierry już odpowiedział, możemy po prostu przyciągnąć operatorów, których potrzebujemy:

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

Lub, jeśli jesteśmy leniwi, możemy pobrać pełny zestaw operatorów. OSTRZEŻENIE: spowoduje to dodanie wszystkich ponad 50 operatorów do pakietu aplikacji i wpłynie na czasy ładowania

import 'rxjs/Rx';

2
import „rxjs / Rx”; łał. i wszystkie moje włosy ciągną się natychmiast. nie mogę uwierzyć, że nie jest to drukowane na całym świecie dla Rxjs / Angular2. dzięki!!!
JimB

Ale często nie pozostawia kłaczków, domyślnie jest to import z czarnej listy. Utwórz nowy kątowy projekt CLI, zobaczysz. Uwielbiam tę wygodę, ale konwencja w miejscach, w których pracuję w Nowym Jorku, nie pozwala tego robić.
Tim Consolazio,

21

Począwszy od rxjs 5.5 , możesz używać operatorów potokowych

import { map } from 'rxjs/operators';

Co jest nie tak z import 'rxjs/add/operator/map';

Kiedy zastosujemy to podejście, mapoperator zostanie do niego załatany observable.prototype i stanie się częścią tego obiektu.

Jeśli później zdecydujesz się usunąć mapoperatora z kodu, który obsługuje obserwowalny strumień, ale nie usunie odpowiedniej instrukcji importu, kod, który implementuje, mappozostaje częścią Observable.prototype.

Gdy producenci pakietów próbują wyeliminować nieużywany kod ( alias tree shaking ), mogą zdecydować o zachowaniu kodu mapoperatora w polu Obserowalnym, nawet jeśli nie jest on używany w aplikacji.

Rozwiązanie -Pipeable operators

Operatory z możliwością potoku są czystymi funkcjami i nie łatają Observable . Można importować operatory za pomocą składni importu ES6, import { map } from "rxjs/operators"a następnie zawinąć je w funkcję, pipe()która przyjmuje zmienną liczbę parametrów, tj. Operatory łańcuchowe.

Coś takiego:

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

16

W Angular 5 import RxJS jest ulepszony.

Zamiast

import 'rxjs/add/operator/map';

Teraz możemy

import { map } from 'rxjs/operators';

Korzystając z tego podejścia, teraz w twojej kompilacji będzie on zawierał tylko używane operatory (w tym przypadku mapę), wcześniej obejmował wszystkich operatorów z biblioteki rxjs. sprawdź poniższy link, aby uzyskać więcej szczegółów. loiane.com/2017/08/angular-rxjs-imports
Hiren Shah

13

Korzystanie Observable.subscribebezpośrednio powinno działać.

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

5
To nie jest bardzo skuteczne podejście. Na przykład, jeśli jest wielu subskrybentów, każdy z nich będzie musiał uruchomić mapę na danych, a nie tylko raz w usłudze. Myślę, że OP miał właściwe podejście, po prostu nie załadował odpowiedniego modułu, aby go użyć.
Evan Plaice,

3

W przypadku wersji Angular 5 i nowszych zaktualizowana linia importowania wygląda następująco:

import { map } from 'rxjs/operators';

LUB

import { map } from 'rxjs/operators';

Również te wersje całkowicie obsługują Pipable Operators, więc możesz łatwo używać .pipe () i .subscribe ().

Jeśli używasz wersji Angular 2, następujący wiersz powinien działać absolutnie dobrze:

import 'rxjs/add/operator/map';

LUB

import 'rxjs/add/operators/map';

Jeśli nadal napotykasz problem, musisz przejść z:

import 'rxjs/Rx';

Nie wolę, abyś używał go bezpośrednio, ponieważ zwiększa to czas ładowania, ponieważ zawiera dużą liczbę operatorów (użytecznych i nieprzydatnych), co nie jest dobrą praktyką zgodnie z normami branżowymi, więc upewnij się najpierw spróbuj użyć wyżej wymienionych linii importujących, a jeśli to nie zadziała, powinieneś wybrać rxjs / Rx


3

Mam rozwiązanie tego problemu

Zainstaluj ten pakiet:

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

następnie zaimportuj tę bibliotekę

import 'rxjs/add/operator/map'

w końcu ponownie uruchom projekt jonowy

ionic serve -l

3

Wersja kątowa 6 „0.6.8” rxjs wersja 6 „^ 6.0.0”

to rozwiązanie jest dla:

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

jak wszyscy wiemy, angular jest rozwijany każdego dnia, więc jest wiele zmian każdego dnia, a to rozwiązanie jest dla Angulara 6 i rxjs 6, które
najpierw pracują z http, należy je zaimportować: w końcu musisz zadeklarować moduł HttpModule w aplikacji. module.ts

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

i musisz dodać HttpModule do Ngmodule -> importowanie

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

po drugie, aby pracować z mapą, należy najpierw zaimportować potok:

import { pipe } from 'rxjs';

po trzecie potrzebujesz importu funkcji mapy z:

import { map } from 'rxjs/operators';

musisz użyć mapy wewnątrz potoku w następujący sposób:

 constructor(public http:Http){  }

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

to działa idealnie, powodzenia!


2

Mapa używasz tutaj, nie jest .map()w javascript, to Rxjs funkcja map, które działa na Observableskątowej ...

W takim przypadku musisz go zaimportować, jeśli chcesz użyć mapy z danymi wynikowymi ...

map(project: function(value: T, index: number): R, thisArg: any): Observable<R> Stosuje daną funkcję projektu do każdej wartości emitowanej przez źródło Observable i emituje otrzymane wartości jako Observable.

Po prostu zaimportuj go w następujący sposób:

import 'rxjs/add/operator/map';

1

Ponieważ usługa HTTP w angular2 zwraca typ Observable , z katalogu instalacyjnego Angular2 (w moim przypadku „node_modules”), musimy zaimportować funkcję mapowania Observable do twojego komponentu za pomocą usługi http , ponieważ:

import 'rxjs/add/operator/map';


1

Po prostu dodaj linię do pliku,

import „rxjs / Rx”;

Spowoduje to zaimportowanie wiązki zależności. Testowane pod kątem 5


0

To prawda, że ​​RxJs podzielił swojego operatora mapy w osobny moduł, a teraz musisz zaimportować go jak każdy inny operator.

import rxjs/add/operator/map;

i wszystko będzie dobrze



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

rozwiąże twój problem

Testowałem to w wersji kątowej 5.2.0 i rxjs 5.5.2


0

dzieje się tak, ponieważ używasz rxjs, a funkcja rxjs nie jest statyczna, co oznacza, że ​​nie możesz wywoływać ich bezpośrednio, musisz wywołać metody wewnątrz potoku i zaimportować tę funkcję z biblioteki rxjs

Ale jeśli używasz rxjs -comp, wystarczy zaimportować operatory rxjs -comp


0

Próbowałem poniżej poleceń i zostało to naprawione:

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


import 'rxjs/Rx';

To tylko po to, abyś początkowo pracował w rxjs 6, wykonując dla ciebie łatanie. Jest to tylko krótkotrwała poprawka i należy dokonać pełnego przejścia do RxJS 6.
HankCa


0

Dodatkowo, co skomentował @ mlc-mlapis, łączysz operatory do wynajęcia i prototypową metodę łatania. Użyj jednego lub drugiego .

W twoim przypadku tak powinno być

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.