Angular2 - 彼此依赖的多个http请求

时间:2016-10-19 19:28:20

标签: angular

我正在通过重新创建我们在工作中开发的应用程序来学习angular2。部分应用需要进行多次http调用。每次通话都取决于前一次通话的结果。我希望第二次,第三次调用等使用前一次调用结果中的id。

我的组件代码和服务代码如下

COMPONENT:

import {Component, OnInit} from '@angular/core';
import {VillageService} from './village.service';

@Component({
    selector: 'village',
    templateUrl: 'app/village/village.component.html',
    styleUrls: ['assets/stylesheets/styles.css'],
    providers: [VillageService]
})

export class VillageComponent implements OnInit {
    villages = [];
    workAreas = [];
    shifts = [];
    roles = [];

    constructor(private _villageService: VillageService){
    }

    ngOnInit() {
        this._villageService.GetAllVillages()
        .subscribe(res => {
            this.villages = res;
        },
        null,
        () => { 
            //Get all work areas for each village
            for(let i = 0; i < this.villages.length; i++){
            this._villageService.GetAllWorkAreas(this.villages[i].VillageId)
                .subscribe(res => {
                    this.workAreas = res;
                },
                null,
                () => { 
                     //Get all shifts for each work area
                    for(let j = 0; j < this.workAreas.length; j++){
                        this._villageService.GetAllShifts(this.workAreas[j].WorkAreaId)
                        .subscribe(res => {
                            this.shifts = res;
                        },
                        null,
                        () => { 
                            //Get all roles for each shift
                            for(let k = 0; k < this.shifts.length; k++){
                               this._villageService.GetAllRoles(this.shifts[k].ShiftId)
                                .subscribe(res => {
                                    this.roles = res;
                                },
                                null,
                                () => { 
                                    this.shifts[k].roles = this.roles;
                                });
                            }  
                            this.workAreas[j].shifts = this.shifts;
                        });
                    }  
                    this.villages[i].workAreas = this.workAreas;
                    console.log(this.villages[i]); 
                });
            }
        });
    }
}

SERVICE:

import { Injectable }     from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map';

@Injectable()
export class VillageService {
    private _baseUrl = "{BASE_URL_ADDRESS_GOES_HERE}";

    constructor(private _http: Http){}

    GetAllVillages() {
        return this._http.get(this._baseUrl + "village/All").map(res =>     res.json());
    }

    GetAllWorkAreas(villageId) {
        return this._http.get(this._baseUrl + "WorkArea/All/" +   villageId).map(res => res.json());
    }

    GetAllShifts(workAreaId) {
        return this._http.get(this._baseUrl + "Shift/All/" + workAreaId).map(res => res.json());
    }

    GetAllRoles(shiftId) {
        return this._http.get(this._baseUrl + "Role/All/" + shiftId).map(res => res.json());
    }
}

代码部分有效。我得到所有村庄各自的工作区域;然而,只有最后一个村庄和工作区才有其变化和作用。猜测我的逻辑有些不对劲但看不出它是什么。我也不喜欢做多个循环,但却想不到另一种方法。

有没有人知道如何更好地做到这一点?我已经尝试过调试,看看发生了什么,但一直陷入困境。

提前致谢。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:3)

在不进入代码细节的情况下,当您使用一个调用的结果(call1 =&gt; call2 =&gt; call3)时,您应该使用的运算符是mergeMap(别名为rxjs中的flatmap)。这看起来有点像这样。

this._villageService.GetAllVillages()
    .flatMap(
       (response) => {
         // take from the response what you want and use it for the next call
         this._villageService.GetAllWorkAreas(//pass the thing from your previous response here)
       }
    )
    .flatMap(
      ....
    )
    .subscribe(...)

对于每个相关的调用,根据需要重复此flatMap。

flatMap的作用是,它对每个值执行一个函数,并期望该函数返回一个observable。在封面下,它将订阅该可观察对象,一旦有了值,它就会将其发送到下一个平面地图。

所以,首先你得到所有的村庄。如果您有此值,它将被发送到第一个flatMap。第一个,将执行另一个请求。一旦该请求完成,结果将过去到下一个flatMap,依此类推......

答案 1 :(得分:0)

变量i和j以及异步js的范围存在问题。当订阅被触发时,i或j已经在循环结束时。这就是为什么你只得到最后一个村庄和工作区的结果。尝试将索引变量包装在一个立即函数中,例如。

for(let i = 0; i < this.villages.length; i++){
  (function(i) {
    your async code...

  })(i);  
}