Angular HTTP GET с ошибкой TypeScript http.get(...). map не является функцией в [null]

У меня проблема с HTTP в Angular.

Я просто хочу GET a JSON список и показать его в представлении.

Класс обслуживания

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

И в HallListComponent я вызываю метод getHalls из службы:

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

Однако я получил исключение:

TypeError: this.http.get(...). map не является функцией в [null]

зал-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"
  ]
}

Ответ 1

Я думаю, что вам нужно импортировать это:

import 'rxjs/add/operator/map'

Или, в общем, это, если вы хотите иметь больше методов для наблюдаемых. ПРЕДУПРЕЖДЕНИЕ. Это импортирует все 50+ операторов и добавит их в ваше приложение, что повлияет на размер вашего пакета и время загрузки.

import 'rxjs/Rx';

Подробнее см. эту проблему.

Ответ 2

Просто какой-то фон... Недавно отчеканенный Server Communication dev guide (наконец) обсуждает/упоминает/объясняет это:

Библиотека RxJS довольно велика. Размер имеет значение, когда мы создаем производственное приложение и развертываем его на мобильных устройствах. Мы должны включать только те функции, которые нам действительно нужны.

Соответственно, Angular предоставляет усеченную версию Observable в модуле rxjs/Observable, версию, в которой отсутствуют почти все операторы, включая те, которые мы хотели бы использовать здесь, например метод map.

Нам нужно добавить необходимые нам операторы. Мы могли бы добавить каждый оператор, один за другим, до тех пор, пока у нас не будет пользовательской реализации Observable, настроенной именно на наши требования.

Так как @Thierry уже ответил, мы можем просто втянуть нужные нам операторы:

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

Или, если мы ленивы, мы можем задействовать полный набор операторов. ПРЕДУПРЕЖДЕНИЕ: это добавит все 50+ операторов в ваш комплект приложений и будет влиять на время загрузки

import 'rxjs/Rx';

Ответ 3

Использование Observable.subscribe напрямую должно работать.

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

Ответ 4

При использовании Angular 5 импорт RxJS улучшен.

Вместо

import 'rxjs/add/operator/map';

Теперь мы можем

import { map } from 'rxjs/operators';

Ответ 5

Используемая здесь карта не является .map() в javascript, это функция отображения Rxjs, работающая на Observables в Angular...

Итак, в этом случае вам нужно импортировать его, если вы хотите использовать карту в результирующих данных...

map(project: function(value: T, index: number): R, thisArg: any): Observable<R> Применяет заданную функцию проекта к каждому испускаемому значению с помощью источника Observable и испускает результирующие значения в виде Наблюдаемое.

Поэтому просто импортируйте его следующим образом:

import 'rxjs/add/operator/map';

Ответ 6

Так как служба Http в angular2 возвращает Наблюдаемый тип, Из вашего каталога установки Angular2 ('node_modules' в моем случае) нам нужно импортировать функцию отображения Observable в компоненте с помощью службы http, как:

import 'rxjs/add/operator/map';

Ответ 7

Глобальный импорт безопасен.

import 'rxjs/Rx';

Ответ 8

import 'rxjs/add/operator/map';

решит вашу проблему

Я тестировал его в angular 5.2.0 и rxjs 5.5.2

Ответ 9

Правда, RxJs отделил оператор отображения в отдельном модуле, и теперь вам нужно явно импортировать его, как и любой другой оператор.

import rxjs/add/operator/map;

и все будет хорошо.