离开带有 Hicharts 图表的页面时无法读取未定义的 属性 'forExport'
Cannot read property 'forExport' of undefined when leaving the page with Hicharts chart
我可以在一个非常简单的 Angular-Hicharts 应用程序中重现该问题。当我从服务器检索数据,然后离开带有 Highcharts 图表的页面时,出现此错误:
Cannot read property 'forExport' of undefined
at a.destroy (highcharts.js:394)
at HighchartsChartComponent.ngOnDestroy (highcharts-angular.js:44)
毫不奇怪,HighchartsChartComponent.ngOnDestroy
是
ngOnDestroy() {
if (this.chart) { // #56
this.chart.destroy();
this.chart = null;
}
}
这是最简单的例子:
export class WeatherForecastComponent implements OnInit {
highcharts: typeof Highcharts = Highcharts;
chartOptions: Highcharts.Options = { ... };
constructor(private http: HttpClient) { }
ngOnInit(): void {
this.http.get<any[]>(`http://localhost:57432/WeatherForecast`, {
headers: new HttpHeaders({
"Content-Type": "application/json"
})})
.subscribe(result => {
let categories: string[] = [];
let dataSeries: number[] = [];
for (let i = 0; i < result.length; i++) {
categories.push(result[i]['location']);
dataSeries.push(result[i]['temperatureC']);
}
this.chartOptions.xAxis = {
categories: categories
};
this.chartOptions.series = [{
type: "column",
name: "Cities",
data: dataSeries
}];
this.highcharts.chart('container', this.chartOptions);
}, error => {
console.log(error);
});
}
}
我在 Stack Overflow 和 Github 上看到了许多类似的问题。我明白根本原因是它试图删除已经删除的图表。但是他们都在删除(或试图删除)应用程序代码中的图表。
我尝试删除 ngOnDestroy()
中的图表或取消订阅 - 但没有区别。
这是repo,包括服务器端代码。
请注意,当它是“硬编码”图表时,不会发生问题。
Angular: 12.2;高字符 9.2.2; Highcharts-Angular: 2.10.0
在您的代码中有一个不必要的东西导致了这个问题。
您不必破坏此处的图表参考。当您删除它时,一切都按预期工作。
ngOnDestroy() {
this.chartRef.destroy()
}
另请注意,在 subscribe
中创建第二个图表并不理想。 Insted 使用 updateFlag
.
this.highcharts.chart('container', this.chartOptions);
演示:https://stackblitz.com/edit/highcharts-angular-basic-line-nxzqvy
主要有两点不起作用。
但在我解释之前,让我们先看看负责在包装器中创建图表的代码。
ngOnChanges(changes) {
const update = changes.update && changes.update.currentValue;
if (changes.options || update) {
this.wrappedUpdateOrCreateChart();
if (update) {
this.updateChange.emit(false); // clear the flag after update
}
}
}
wrappedUpdateOrCreateChart() {
if (this.runOutsideAngular) {
this._zone.runOutsideAngular(() => {
this.updateOrCreateChart();
});
}
else {
this.updateOrCreateChart();
}
}
updateOrCreateChart() {
if (this.chart && this.chart.update) {
this.chart.update(this.options, true, this.oneToOne || false);
}
else {
this.chart = this.Highcharts[this.constructorType || 'chart'](this.el.nativeElement, this.options, this.callbackFunction || null);
// emit chart instance on init
this.chartInstance.emit(this.chart);
}
}
如您所见,一切都发生在ngOnChanges
钩子中。如果检测到更改,则会触发一系列方法以最终更新图表。
现在不起作用的东西:
如果 subscribe
中发生任何异步代码(例如 HTTP 请求 - 在我的示例中被 setTimeout
模拟),您必须手动设置包装器应该通过设置 updateFlag
来更新。因为 Angular 没有检测到 chartOptions
.
中某些属性的变化
如果您像下面的代码片段一样将属性分配给 chartOptions
,请将 oneToOne
标志设置为 true
this.chartOptions.xAxis = {
categories: categories
};
this.chartOptions.series = [{
type: "column",
name: "Cities",
data: dataSeries
}];
文档:https://github.com/highcharts/highcharts-angular#options-details
演示:https://stackblitz.com/edit/highcharts-angular-basic-line-vwrrmx
我可以在一个非常简单的 Angular-Hicharts 应用程序中重现该问题。当我从服务器检索数据,然后离开带有 Highcharts 图表的页面时,出现此错误:
Cannot read property 'forExport' of undefined at a.destroy (highcharts.js:394) at HighchartsChartComponent.ngOnDestroy (highcharts-angular.js:44)
毫不奇怪,HighchartsChartComponent.ngOnDestroy
是
ngOnDestroy() {
if (this.chart) { // #56
this.chart.destroy();
this.chart = null;
}
}
这是最简单的例子:
export class WeatherForecastComponent implements OnInit {
highcharts: typeof Highcharts = Highcharts;
chartOptions: Highcharts.Options = { ... };
constructor(private http: HttpClient) { }
ngOnInit(): void {
this.http.get<any[]>(`http://localhost:57432/WeatherForecast`, {
headers: new HttpHeaders({
"Content-Type": "application/json"
})})
.subscribe(result => {
let categories: string[] = [];
let dataSeries: number[] = [];
for (let i = 0; i < result.length; i++) {
categories.push(result[i]['location']);
dataSeries.push(result[i]['temperatureC']);
}
this.chartOptions.xAxis = {
categories: categories
};
this.chartOptions.series = [{
type: "column",
name: "Cities",
data: dataSeries
}];
this.highcharts.chart('container', this.chartOptions);
}, error => {
console.log(error);
});
}
}
我在 Stack Overflow 和 Github 上看到了许多类似的问题。我明白根本原因是它试图删除已经删除的图表。但是他们都在删除(或试图删除)应用程序代码中的图表。
我尝试删除 ngOnDestroy()
中的图表或取消订阅 - 但没有区别。
这是repo,包括服务器端代码。
请注意,当它是“硬编码”图表时,不会发生问题。
Angular: 12.2;高字符 9.2.2; Highcharts-Angular: 2.10.0
在您的代码中有一个不必要的东西导致了这个问题。
您不必破坏此处的图表参考。当您删除它时,一切都按预期工作。
ngOnDestroy() {
this.chartRef.destroy()
}
另请注意,在 subscribe
中创建第二个图表并不理想。 Insted 使用 updateFlag
.
this.highcharts.chart('container', this.chartOptions);
演示:https://stackblitz.com/edit/highcharts-angular-basic-line-nxzqvy
主要有两点不起作用。 但在我解释之前,让我们先看看负责在包装器中创建图表的代码。
ngOnChanges(changes) {
const update = changes.update && changes.update.currentValue;
if (changes.options || update) {
this.wrappedUpdateOrCreateChart();
if (update) {
this.updateChange.emit(false); // clear the flag after update
}
}
}
wrappedUpdateOrCreateChart() {
if (this.runOutsideAngular) {
this._zone.runOutsideAngular(() => {
this.updateOrCreateChart();
});
}
else {
this.updateOrCreateChart();
}
}
updateOrCreateChart() {
if (this.chart && this.chart.update) {
this.chart.update(this.options, true, this.oneToOne || false);
}
else {
this.chart = this.Highcharts[this.constructorType || 'chart'](this.el.nativeElement, this.options, this.callbackFunction || null);
// emit chart instance on init
this.chartInstance.emit(this.chart);
}
}
如您所见,一切都发生在ngOnChanges
钩子中。如果检测到更改,则会触发一系列方法以最终更新图表。
现在不起作用的东西:
如果
中某些属性的变化subscribe
中发生任何异步代码(例如 HTTP 请求 - 在我的示例中被setTimeout
模拟),您必须手动设置包装器应该通过设置updateFlag
来更新。因为 Angular 没有检测到chartOptions
.如果您像下面的代码片段一样将属性分配给
chartOptions
,请将oneToOne
标志设置为true
this.chartOptions.xAxis = {
categories: categories
};
this.chartOptions.series = [{
type: "column",
name: "Cities",
data: dataSeries
}];
文档:https://github.com/highcharts/highcharts-angular#options-details
演示:https://stackblitz.com/edit/highcharts-angular-basic-line-vwrrmx