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

时间:2021-05-24 00:26:39

I'm currently trying to teach myself Angular2 and TypeScript after happily working with AngularJS 1.* for the last 4 years! I have to admit I am hating it but I am sure my eureka moment is just around the corner... anyway, I have written a service in my dummy app that will fetch http data from a phoney backend I wrote that serves JSON.

在过去的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');
    }   
}

Now in a Component I wish to run (or chain) both getUserInfo() and getUserPhotos(myId) methods. In AngularJS this was easy as in my controller I would do something like this to avoid the "Pyramid of doom"...

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

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

Now I have tried doing something similar in my component (replacing .then for .subscribe) however my error console going crazy!

现在我尝试在我的组件中做类似的事情(替换.then for .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;
            });
    }

}

I'm obviously doing something wrong... how would I best with Observables and RxJS? Sorry if I am asking stupid questions... but thanks for the help in advance! I have also noticed the repeated code in my functions when declaring my http headers...

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

1 个解决方案

#1


109  

For your use case, I think that the flatMap operator is what you need:

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

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

This way, you will execute the second request once the first one is received. The flatMap operator is particularly useful when you want to use the result of the previous request (previous event) to execute another one. Don't forget to import the operator to be able to use it:

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

import 'rxjs/add/operator/flatMap';

This answer could give you more details:

这个答案可以给你更多细节:

If you want to only use subscribe method, you use something like that:

如果你只想使用subscribe方法,你可以使用类似的东西:

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

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

To finish, if you would want to execute both requests in parallel and be notified when all results are then, you should consider to use Observable.forkJoin (you need to add import 'rxjs/add/observable/forkJoin'):

要完成,如果你想并行执行两个请求并在所有结果都被通知时,你应该考虑使用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];
});

#1


109  

For your use case, I think that the flatMap operator is what you need:

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

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

This way, you will execute the second request once the first one is received. The flatMap operator is particularly useful when you want to use the result of the previous request (previous event) to execute another one. Don't forget to import the operator to be able to use it:

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

import 'rxjs/add/operator/flatMap';

This answer could give you more details:

这个答案可以给你更多细节:

If you want to only use subscribe method, you use something like that:

如果你只想使用subscribe方法,你可以使用类似的东西:

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

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

To finish, if you would want to execute both requests in parallel and be notified when all results are then, you should consider to use Observable.forkJoin (you need to add import 'rxjs/add/observable/forkJoin'):

要完成,如果你想并行执行两个请求并在所有结果都被通知时,你应该考虑使用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];
});