大家早上好。我是Angular2的新手,在我正在研究的项目中,我必须发出一些HTTP请求才能从REST后端检索数据。
从后端我必须得到一个模块列表。每个模块都有一个或多个操作。表示两个实体的typescript类如下
export class Module {
public name: string;
public htmlPath: string;
public actions: ModuleAction[];
constructor(data: IModule){
this.name = data.name;
this.actions = [];
this.htmlPath = data.htmlPath;
}
addAction(action: ModuleAction): void {
this.actions.push(action);
}
}
export class ModuleAction {
private name: string;
constructor(data: IModuleAction){
this.name = data.actionName;
}
}
支持公开调用以检索没有相关操作的模块列表,并公开第二个端点以检索给定模块的操作列表。为了初始化我的角度接口,我必须发出第一个HTTP请求来获取模块列表。一旦获得模块,我必须为每个模块发出第二个请求,以检索操作并更新Module实例。
昨天我尝试使用RxJS来获取数据。我找到的唯一可行的解决方案是以下
getModules(type?: string) : Observable<Module[]> {
let url = ...
console.log("getting modules");
return this.http.get(url)
.map(res => {
let body = res.json();
let modules = body.map(jsModule => {
let m = new Module(jsModule);
let url = HttpHandlerService.URL_INFO + '/' + m.htmlPath;
console.log("getting actions for module " + m.name);
this.http.get(url)
.map(response => {
let body = response.json();
return body.actions.map(function(a : IModuleAction){
return new ModuleAction(a);
});
})
.subscribe(actions => {
for(let a of actions)
m.addAction(a);
});
return m;
});
return modules;
})
.catch(this.handleError);
}
我很确定我错误地使用了RxJS运算符,并且必须有一个不同的解决方案才能以更“符合RxJS”的方式获得相同的结果。
如何使用RxJS运算符来获得相同的结果? 非常感谢你的帮助。
答案 0 :(得分:3)
使用Observable.flatMap
运算符可以实现链接相互依赖的HTTP请求。请参阅此帖子:Angular 2 - Chaining http requests
而且,由于您需要检索每个模块的模块操作,请使用Observable.forkJoin
运算符。请参阅此帖子:Send multiple HTTP GET requests in parallel
最终结构如下所示:
getModules()
.flatMap(modules => {
this.modules = modules;
let moduleActionsObservables = modules.map(module => {
return this.getModuleActions(module);
});
return Observable.forkJoin(moduleActionsObservables);
})
.map(result) => {
// module actions for each module
console.log(result); // => [[ModuleAction, ModuleAction], [ModuleAction], [ModuleAction, ModuleAction]]
// if you want to assign them to their respective module, then:
this.modules.forEach((module, i) => {
module.actions = result[i];
});
return this.modules;
});
// The result:
this.getModules().subscribe(
modules => {
console.log(modules); // => [{moduleId: '123', actions: [..]}, {moduleId: '124', actions: [..]}]
});
答案 1 :(得分:0)
尝试进行一些分色并使用switchMap:
getModules(type?: string) : Observable<Module[]> {
let url = ...
console.log("getting modules");
return this.http.get(url)
.switchMap(res => {
let body = res.json();
return getJsModules(body);
})
.catch(this.handleError);
}
getJsModules(body){
return body.switchMap(jsModule => {
let m = new Module(jsModule);
let url = HttpHandlerService.URL_INFO + '/' + m.htmlPath;
console.log("getting actions for module " + m.name);
return getModuleActions.map(actions => {
for(let a of actions)
m.addAction(a);
});
});
}
getModuleActions(url){
return this.http.get()
.switchMap(response => {
let body = response.json();
return body.actions.map(function(a : IModuleAction){
return new ModuleAction(a);
});
})
}
答案 2 :(得分:0)
我会使用flatMap和forkJoin:
this.http.get(url)
.flatMap(t=> {
let urls = getUrls(t.json())
.map(url=> this.http.get(url).map(t=>getActions(t.json()));
return Observable.forkJoin(urls).map(x=> [].concat(...x));
}
//.subscribe => [ModuleAction, ModuleAction, ModuleAction,...]
其中
getUrls(body:[]): string[] {
return body.map(jsModule => {
let m = new Module(jsModule);
let url = HttpHandlerService.URL_INFO + '/' + m.htmlPath;
return url;
};
}
getActions(body:any): ModuleAction[] {
return body.actions.map((a:IModuleAction) => new ModuleAction(a));
}