我在angular中有一个http服务,该服务返回txt / html,我解析响应以查找任何iframe标签,对于每个iframe,我都调用相同的服务来获取内部html,而该内部html也可以具有iframe标签,因此上。 进行此递归调用,直到没有更多iframe可供提取为止。 我想做的是每次都处理和更新响应(覆盖iframe的src)。
//service
getHtmlFile(file: string) {
const httpOptions = {
headers: new HttpHeaders('X-Requested-With': 'XMLHttpRequest'}),
//observe: 'response' as 'response',
responseType: 'text' as 'text'
};
return this.http.get(url, httpOptions); //set headers
}
//Not working
getHtml(file: string) {
this.httpService.getHtmlFile(file)
.subscribe(res => {
const iframes = getIframes(res); //get list of iframes from res.
//loop through the list and recursively get html files
for (let i = 0; i < iframes.length; i++) {
const src = extractSrc(iframes[i]);//extract the src attribute
this.getHtml(src);//recursive call
res = res.replace(iframes[i], newvalue); //want to update res here?
}
return res;
});
}
我可以为每个请求执行此操作,但无法弄清楚如何累积递归调用中的更改,以便父html res可以从其子级获得更改。订户只会得到应用了所有更改的最终结果。不确定该服务如何与可观察到的响应一起工作?
不确定是否清楚,但是简而言之,它是树状结构,其中每个节点值(来自Observable)都应注入/替换为其父值(同样来自Observable)!
这是Angular 5。
可以在角度 expand 选项中使用,但是不确定如何使用它维护树结构。这是一个类似的问题link
//编辑
很抱歉,我想达到的目标尚不清楚。这是输入文件和所需输出结果的示例。希望这现在有意义。
//index.html
<html>
<body>
<!-- iframes -->
<iframe src="file1.html"></iframe>
<iframe src="file2.html"></iframe>
</body>
</html>
//file1.html
<html>
<body>
<!-- iframes -->
<iframe src="file1_1.html"></iframe>
</body>
</html>
//file2.html
<html>
<body>
<!-- body with no iframes -->
</body>
</html>
//file1_1.html
<html>
<body>
<!-- body with no iframes -->
</body>
</html>
输出应为顶级index.html,其中iframe src为blob,如下所示。 此处的关键是file1 / file2的iframe src也应设置为blob,然后在索引帧中将其iframe src设置为blob,等等。
<html>
<body>
<!-- iframes -->
<iframe src="blob(file1)"></iframe>
<iframe src="blob(file2)"></iframe>
</body>
</html>
答案 0 :(得分:0)
这不会解决您的全部问题,但是部分问题是您需要订阅服务。否则,该功能将在您完成处理之前终止。
getHtml = (file: string): Observable<any>{
return new Observable<any>(observer => {
this.httpService.getHtmlFile(file)
.subscribe(res => {
const iframes = getIframes(res);
for (let i = 0; i < iframes.length; i++) {
const index = i; // not sure if you need this, but you might lose scope in your loop
const src = extractSrc(iframes[i]);
this.getHtml(src).subscribe(newRes => {
res = res.replace(iframes[inex], newRes);
});
}
observer.next(res);
observer.complete();
});
});
}
编辑,该解决方案利用了rxjs Observable
答案 1 :(得分:0)
我认为这完全符合您的编码方式。在我看来,这里的关键是您在返回价值,但是没人期望它。我要做的是将最终值存储到变量中,而不是返回它。
为了将行为隔离到服务中,我还使用了concatMap。现在,我想这就是您想要的:
//service
getHtmlFile(file: string) {
const httpOptions = {
headers: new HttpHeaders(
{
'X-Requested-With': 'XMLHttpRequest',
}),
//observe: 'response' as 'response',
responseType: 'text' as 'text'
};
//set headers
return this.http.get(url, httpOptions).pipe(
concatMap( (res) => {
//get list of iframes from res.
const iframes = getIframes(res);
//loop through the list and recursively get html files
for (let i = 0; i < iframes.length; i++) {
//extract the src attribute
const src = extractSrc(iframes[i]);
//recursive call
this.getHtml(src);
//want to update res here?
res = res.replace(iframes[i], newvalue);
}
return res;
}));
}
//not working
getHtml(file: string) {
this.httpService.getHtmlFile(file)
.subscribe( res => {
this.variableInComponent = res;
});
}
这样,您可以将循环和递归调用隔离到第一个函数中,并将其设为私有。每次调用getHtml时,在订阅执行之前,concatMap块都会执行操作并返回要订阅的值。
无论如何,我都不了解您想要实现的目标,但是我认为这种可观察的模式中的递归调用存在一些问题...