吼
在我的项目中,我想通过点击页面上的一个按钮来导出(PDF)。在我的页面中,我有一个动态创建多个图表的仪表盘。当我点击 "export "按钮时,我想通知每个动态组件从当前的图表实例中创建一个svg,并将其传递给 "page "组件。为了能够创建一个svg,我必须等到一个图表实例被创建。当我从不同的动态组件中得到所有的svg时,我就可以将信息(不同的svg)传递到api调用的主体中,从而创建一个pdf。
所以我尝试在一个 测试项目. 我不知道正确的方法,所以我试着从服务中用动态组件中的观测值来填充一个数组,我的问题是如何知道所有动态组件中的观测值(失败时返回SVG或错误)都被添加到数组中,然后再在动态组件中做forkjoin。
我遇到的问题是,我如何知道所有来自动态组件的观测值(当它失败时,会返回SVG或错误)都被添加到数组中,然后才在 着陆页 组件。我的forkJoin也没有返回svg,所以我做错了什么。但也许有一个更好的方法,就是等待所有的动态组件,直到他们创建他们的svg's。
我认为问题是,当 chartInstanceStream$
发出,它没有订阅者,这意味着它无法完成,因 first()
这也意味着 forkJoin
不会发射,除非所有提供的观测值至少发射一次并完成。
chartInstanceStream$
发射的原因是 setChartInstance
,这发生在 testService.clickExportPdfStream
发射。
一个快速的解决方案是将 chartInstanceStream
变成 ReplaySubject
以致于 重播 的最新值到 迟交者.
所以,从这个,
chartInstanceStream$ = new Subject<Highcharts.Chart>();
到这个
chartInstanceStream$ = new ReplaySubject<Highcharts.Chart>(1);
forkJoin
内部订阅了所有提供的观测值。通过将 chartInstanceStream$
变成 ReplaySubject
你要确保迟来的用户(那些来自中国的用户)。forkJoin
)将接收到最古老的由 ReplaySubject
.
而且因为你的可观察的东西 forkJoin
认购是这样的。
this.chartInstanceStream$.pipe(
map((chart: Highcharts.Chart) =>
chart.getSVG()
),
first() // !
)
在它们发出一个值后,它们会立即完成,由于... ... first()
.
像你这样使用service的方法是一种方法。
另一种解决方案可能是导出一个 public
函数,然后从你的父组件中调用它们。
例如,我有这个简单的 ChartComponent
模仿svg导出。
@Component({
selector: "app-chart",
templateUrl: "./chart.component.html",
styleUrls: ["./chart.component.css"]
})
export class ChartComponent {
exportSvg(): Observable<string> {
return defer(() =>
timer(Math.random() * 2000 + 500).pipe(mapTo('svg'))
)
}
}
现在在我的父组件中,我查询这些组件并调用 exportSvg
的需求。
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
@ViewChildren(ChartComponent) charts: QueryList<ChartComponent>;
onExportClick(): void {
const charts = this.charts.map(component => component.exportSvg());
forkJoin(charts).subscribe(console.log)
}
}
在我的例子中,我没有创建 ChartComponent
的动态,但它的行为应该是一样的。
完整的例子可以在 这场突击赛