首页 文章

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

提问于
浏览
77

在过去的4年里,我正在努力与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中这很容易,因为在我的控制器中我会做这样的事情以避免"Pyramid of doom" ...

// 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标头时,我也注意到我的函数中重复的代码...

1 回答

  • 116

    对于您的用例,我认为 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];
    });
    

相关问题