我正在通过重新创建我们在工作中开发的应用程序来学习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());
}
}
代码部分有效。我得到所有村庄各自的工作区域;然而,只有最后一个村庄和工作区才有其变化和作用。猜测我的逻辑有些不对劲但看不出它是什么。我也不喜欢做多个循环,但却想不到另一种方法。
有没有人知道如何更好地做到这一点?我已经尝试过调试,看看发生了什么,但一直陷入困境。
提前致谢。任何帮助表示赞赏。
答案 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);
}