Why is my chart attempting to read notifyPlugins('beforeDestroy') when navigating away from the page of the chart?
I have a plugins file, a svelte action and a main file [ChartMetrics.svelte] (where the action is used). The current behaviour is that the chart loads completely fine in the main page, but when navigating to another page I am met with the notifyPlugins error. I have added the most relevant code from my project, as the entire codebase is quite large so would be unable to add it to a codesandbox. Has anyone recieved this error with notifyPlugins before when working with chart.js? If there is any more code you need to see let me know.
console error:
chart.js:6171 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'notifyPlugins')
at destroy (chart.js:6171:1)
at Object.destroy [as d] (ChartMetrics.svelte:454:1)
at Object.destroy [as d] (Div.svelte:127:1)
at destroy_component (index.mjs:1974:1)
at Object.destroy [as d] (ChartMetrics.svelte:127:1)
at Object.destroy [as d] (ChartMetrics.svelte:535:1)
at destroy_component (index.mjs:1974:1)
at Object.destroy [as d] (EffectiveMaterialAssetsMetricsContainer.svelte:71:1)
at Object.destroy [as d] (MetricWrapper.svelte:133:1)
at Object.destroy [as d] (MetricWrapper.svelte:308:1)
chart.js (line 6171):
destroy() {
this.notifyPlugins('beforeDestroy');
....
}
ChartMetrics (line 454):
d: function destroy(detaching) {
if (detaching) detach_dev(div0);
if_blocks[current_block_type_index].d();
destroy_component(tooltipinfo);
destroy_component(anchor);
if (detaching) detach_dev(t3);
if (detaching) detach_dev(div1);
mounted = false;
dispose();
}
ChartMetrics line 454 (image):
plugins.ts:
export function textPlugin(value: number, theme: Theme) {
return {
id: "chartTextPlugin",
// Plugin for writing text in middle of chart
beforeDraw: function (chart: ChartType) {
plugin that draws some text on a chart.js chart
},
}
}
export function curvePlugin() {
// Curve edges of donut
return {
id: "chartCurvePlugin",
afterUpdate: function (chart: ChartType) {
// some code to curve the edges of the chart.js chart
}
},
afterDraw: function (chart: ChartType) {
// some more code to do same as above
},
}
}
add-chart.ts (svelte action)
export const addChart = (node: HTMLElement, params: ChartProps): ChartGauge => {
const text = textPlugin(params.value, params.theme)
const curve = curvePlugin()
const backgroundColor = mapTypeToColor(params.theme)
return new Chart(node, {
type: "doughnut",
data: {
datasets: [
{
//label: params.caption,
data: [params.value, 100 - params.value],
backgroundColor: backgroundColor,
borderColor: ["rgba(255, 255, 255 ,1)"],
borderWidth: 0,
},
],
},
options: {
rotation: -90,
cutout: "85%",
circumference: 180,
radius: "85%",
responsive: true,
maintainAspectRatio: true,
aspectRatio: 3,
},
plugins: [text, curve],
})
}
ChartMetrics.svelte
{#if value >= 0 && value <= 100}
<CardDiv p={4} pl={4} pr={4}>
<div class="metrics-header">
<h3>
Controls -
{#if titleUrl}
<Anchor href={titleUrl} size={14}>{title}</Anchor>
{:else}
<span>{title}</span>
{/if}
<TooltipInfo content={tooltipContent} id="info" width="small" />
</h3>
<Anchor href={assuranceUrl} size={14}>View Assurance</Anchor>
</div>
<div class="chart">
<canvas
id="chart"
data-test-id="chart"
use:addChart={{ value, theme }}
style="height:100%;width:100%;"
/>
</div>
</CardDiv>
{:else}
<MetricsError message="Chart Metrics Widget Error: Invalid value." />
{/if}
You could try this patch of a solution: in add-chart.ts
instead of
return new Chart(node, {
.....
});
use
const chart = new Chart(node, {
.....
});
chart.destroy = chart.destroy.bind(chart);
return chart;
A more svelte-idiomatic way might be
return {
...chart,
destroy(){
chart.destroy();
}
}
but that would probably need some typescript acrobatics to pass type-checking.