使用TypeScript从Angular2中的http数据链接RxJS Observables


95

在过去四年中愉快地使用AngularJS 1. *之后,我目前正在尝试自学Angular2和TypeScript!我必须承认我很讨厌它,但是我确定我的尤里卡时刻就在眼前。。。无论如何,我已经在虚拟应用程序中编写了一项服务,该服务将从我编写的提供JSON的电话后端获取http数据。

import {Injectable} from 'angular2/core';
import {Http, Headers, Response} from 'angular2/http';
import {Observable} from 'rxjs';

@Injectable()
export class UserData {

    constructor(public http: Http) {
    }

    getUserStatus(): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get('/restservice/userstatus', {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    getUserInfo(): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get('/restservice/profile/info', {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    getUserPhotos(myId): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get(`restservice/profile/pictures/overview/${ myId }`, {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    private handleError(error: Response) {
        // just logging to the console for now...
        console.error(error);
        return Observable.throw(error.json().error || 'Server error');
    }   
}

现在,在组件中,我希望同时运行和链接getUserInfo()getUserPhotos(myId)方法。在AngularJS中,这很容易,因为在我的控制器中,我会做类似的事情来避免“厄运金字塔” ...

// Good old AngularJS 1.*
UserData.getUserInfo().then(function(resp) {
    return UserData.getUserPhotos(resp.UserId);
}).then(function (resp) {
    // do more stuff...
}); 

现在,我尝试在组件中执行类似的操作(替换.then.subscribe),但是我的错误控制台发疯了!

@Component({
    selector: 'profile',
    template: require('app/components/profile/profile.html'),
    providers: [],
    directives: [],
    pipes: []
})
export class Profile implements OnInit {

    userPhotos: any;
    userInfo: any;

    // UserData is my service
    constructor(private userData: UserData) {
    }

    ngOnInit() {

        // I need to pass my own ID here...
        this.userData.getUserPhotos('123456') // ToDo: Get this from parent or UserData Service
            .subscribe(
            (data) => {
                this.userPhotos = data;
            }
        ).getUserInfo().subscribe(
            (data) => {
                this.userInfo = data;
            });
    }

}

我显然做错了什么...如何最好地使用Observables和RxJS?对不起,如果我问的是愚蠢的问题……但是,感谢您的提前帮助!在声明http标头时,我也注意到函数中重复的代码...

Answers:


137

对于您的用例,我认为flatMap您需要的是运算符:

this.userData.getUserPhotos('123456').flatMap(data => {
  this.userPhotos = data;
  return this.userData.getUserInfo();
}).subscribe(data => {
  this.userInfo = data;
});

这样,您将在收到第一个请求后执行第二个请求。flatMap当您要使用上一个请求的结果(上一个事件)执行另一个请求时,该运算符特别有用。不要忘记导入运算符以能够使用它:

import 'rxjs/add/operator/flatMap';

该答案可以为您提供更多详细信息:

如果只想使用subscribe方法,则可以使用以下方法:

this.userData.getUserPhotos('123456')
    .subscribe(
      (data) => {
        this.userPhotos = data;

        this.userData.getUserInfo().subscribe(
          (data) => {
            this.userInfo = data;
          });
      });

最后,如果您想并行执行两个请求并在所有结果都得到通知时得到通知,则应考虑使用Observable.forkJoin(需要添加import 'rxjs/add/observable/forkJoin'):

Observable.forkJoin([
  this.userData.getUserPhotos(),
  this.userData.getUserInfo()]).subscribe(t=> {
    var firstResult = t[0];
    var secondResult = t[1];
});

但是我确实得到了错误“ TypeError:source.subscribe不是[null]中的函数”
Mike Sav

您在哪里遇到此错误?什么时候打电话this.userData.getUserInfo()
Thierry Templier

3
哦! 我的回答中有一个错字:this.userData.getUserPhotos(), this.userData.getUserInfo()而不是this.userData.getUserPhotos, this.userData.getUserInfo()。抱歉!
Thierry Templier,2016年

1
为什么选择flatMap?为什么不切换地图?我假设如果最初的GET请求突然为User输出另一个值,那么您就不想继续为User的先前值获取图像
f.khantsis

4
对于任何想看看它并想知道为什么它不起作用的人:在RxJS 6中,import和forkJoin语法都稍有改变。现在,您需要添加import { forkJoin } from 'rxjs';以导入功能。另外,forkJoin不再是Observable的成员,而是一个单独的函数。因此,Observable.forkJoin()不仅仅是forkJoin()
巴斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.