尝试将多个observable合并为Angular 2项目

时间:2016-11-01 11:26:00

标签: angular typescript rxjs observable

我试图了解RxJs中的Observables。我有一个页面,我需要显示特定网站的所有用户。 User和SiteUser实体位于不同的API端点中。我有以下端点

userService.getSiteUsers(siteId: string): Observable<SiteUser[]>;

其中

export class SiteUser {
    site_id: string;
    user_id: string;
}

userService.getUser(user_id: string): Observable<User>;

,其中

export class User {
    id: string;
    name: string;
    email: string;
    ....
}

所以我必须做以下事情:

  1. 调用siteUsers API以获取特定网站的所有用户ID
  2. 对于每个用户ID,请进行getUser API调用以获取用户详细信息
  3. 我可以很容易地做到这一点

    let users: User[] = []; // this is bound in html view to a table
    this.userService.getSiteUsers("my site id")
                    .subscribe((siteUsers) => {
                        for (let siteUser of siteUsers) {
                            this.userService.getUser(siteUser.user_id)
                                            .subscribe((user) => {
                                                users.push(user);
                                            });
                        }
                    });
    

    但这种方法感觉很脏或很麻烦。我确信有一种更清晰的Observable方法。我是Observables的新手,但据我所知,我应该可以做这样的事情(不是selectMany和mergeAll函数只是我的猜测,我尝试过它并没有用,我甚至找不到selectMany在rxjs库))

    获取网站用户可观察数组 - &gt;对于可观察数组中的每个元素,创建用户可观察 - &gt;将它们全部合并到可观察的用户数组中 - &gt;订阅,所以像这样:

    this.userService.getSiteUsers("my site id") 
                    .selectMany((siteUser) => this.userService.getUser(user))
                    .mergeAll()
                    .subscribe((users) => {
                        this.users = users; 
                    });
    

    有人可以帮助,我无法让它工作

    EDIT ------

    也许是这样的

    this.userService.getSiteUsers("my site id")
        .switchMap(
           (siteUsers) => {
             let userQueries: Observable<User>[] = [];
             for (let siteUser of siteUsers) {
                userQueries.push(this.userService.getUser(siteUser.user_id));
             }
    
             return Observable.forkJoin(userQueries);
           }
        )
        .subscribe((users) => {
            this.users = users;
        });
    

2 个答案:

答案 0 :(得分:6)

如果一个http呼叫依赖于另一个http呼叫,您应该使用.flatMap() / .mergeMap()运营商。

例如在你的情况下会有类似的事情,

this.userService.getSiteUsers("my site id")
.switchMap(
   (siteUsers) => {
     let userQueries: Observable<User>[] = [];
     for (let siteUser of siteUsers) {
        userQueries.push(this.userService.getUser(siteUser.user_id));
     }

     return Observable.forkJoin(userQueries);
   }
)
.subscribe((users) => {
    this.users = users;
});

答案 1 :(得分:1)

尝试这样的事情:

this.userService.getSiteUsers("my site id")
  .flatMap((siteUsers) => {
    // map every user into an array of observable requests
    const usersObservables = siteUsers.map(siteUser => this.userService.getUser(siteUser.user_id)).map((res:Response) => res.json())
    return Observable.forkJoin(...usersObservables)
  }).subscribe(users => {
      //you have all your users now;
      console.log(users)
  });

我们在这里使用spread运算符:

return Observable.forkJoin(...usersObservables)

所以我们将数组转换为参数,如下所示:

return Observable.forkJoin(observableUser1, observableUser2, observableUser...)