Почему моя диаграмма пытается прочитать notifyPlugins('beforeDestroy') при переходе со страницы диаграммы?
У меня есть файл плагинов, действие svelte и основной файл [ChartMetrics.svelte] (где используется действие). Текущее поведение заключается в том, что диаграмма полностью загружается на главной странице, но при переходе на другую страницу я встречаюсь с ошибкой notifyPlugins. Я добавил наиболее подходящий код из своего проекта, так как вся кодовая база довольно велика, поэтому я не смогу добавить ее в коды и ящик. Кто-нибудь получал эту ошибку с notifyPlugins раньше при работе с chart.js? Если есть еще код, который вам нужно увидеть, дайте мне знать.
ошибка консоли:
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 (строка 6171):
destroy() {
this.notifyPlugins('beforeDestroy');
....
}
ChartMetrics (строка 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();
}
Строка 454 ChartMetrics (изображение):
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 (стройное действие)
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}
Да, это на картинке chartjserror, которую я связал. Будет ли это проблемой с chartjs?
Нет, я думаю, причина в том, как код из компонента svelte ChartMetrics вызывает destroy. Не могли бы вы опубликовать, что там около строки 454?
Конечно, я отредактировал свой вопрос, чтобы поместить полный код, где вызывается уничтожение.
Теперь у нас есть проблема узнать, как называется d, чтобы this было undefined. Это ваш код или из импортированной библиотеки (в гугле ничего не нашел)? Вы можете добавить функционирующую/упрощенную версию вашего кода для полной отладки в stackblitz или codeandbox. Кроме того, в качестве дружеского примечания, для будущих сообщений на SO, люди здесь, как правило, неприятно реагируют на код, помещенный в изображения, об этом также есть метассылка.
Да, это компонент моего кода. Я отредактирую ответ как можно большим количеством кода и заменю изображения кодом.
Я обновил вопрос, моя кодовая база слишком велика, чтобы поместить ее в рабочую среду codeandbox, поэтому я добавил к вопросу. Если есть какой-либо другой код, который вы хотели бы увидеть, дайте мне знать, все еще не продвинулся вообще в отношении этой ошибки.
Я расскажу вам, как бы я поступил, если бы мог отладить код: я бы поставил console.info(this) в d() непосредственно перед destroy и попытался увидеть, какое свойство this является экземпляром диаграммы (или, может быть, this является подклассом Chart, или, возможно, есть другой способ получить экземпляр диаграммы) и изменить destroy() на destroy.call(chartInstance). Экземпляр диаграммы — это объект, обладающий такими свойствами, как canvas, chartArea, boxes
Таким образом, функция d() на самом деле не является частью моего ChartMetrics.svelte, то, что я вижу в ChartMetrics.svelte в инспекторе браузера, сильно отличается от того, что есть в моей IDE. Полный файл ChartMetrics.svelte из моей IDE находится здесь: stackblitz.com/edit/… а это версия инспектора браузера: stackblitz.com/edit/…






Вы можете попробовать этот патч решения: в add-chart.ts вместо
return new Chart(node, {
.....
});
использовать
const chart = new Chart(node, {
.....
});
chart.destroy = chart.destroy.bind(chart);
return chart;
Более стройный идиоматический способ мог бы быть
return {
...chart,
destroy(){
chart.destroy();
}
}
но для этого, вероятно, потребуется некоторая акробатика машинописного текста, чтобы пройти проверку типов.
@ ou9hwq93weiq, пожалуйста, дайте мне знать, что произойдет, если вы сделаете первое изменение; мы здесь на пути проб и ошибок
Эй, извините, я только что вернулся к компьютеру. Я только что попробовал ваше решение, и оно работает! Не могли бы вы объяснить, что происходит с svelte-идиоматическим образом? Вы перезаписываете функцию уничтожения для файла ChartMetrics и заменяете ее функцией уничтожения диаграмм?
Просто чтобы уточнить, оба метода работают, но просто хотите понять, что происходит, когда вы говорите «chart.destroy = chart.destroy.bind(chart)»?
Таким образом, проблема заключалась в том, что метод уничтожения по умолчанию, созданный svelte (в вашем сгенерированном файле в строке 381), просто взял метод destroy из экземпляра диаграммы и вызвал его с undefined контекстом (this), см. исходный код.
Первый метод использует bind, поэтому функция destroy всегда связана с экземпляром диаграммы, независимо от того, как она вызывается, this будет этим экземпляром.
Второй метод — предоставить явное destroy для svelte вместо стандартного. По сути, это одно и то же, svelte будет вызывать этот метод, но как бы он ни назывался, он заботится о том, чтобы вызов destroy диаграммы был правильным, то есть chart.destroy(), а не просто destroy.
Я сказал, что мне это кажется более идиоматичным, так как я видел во многих примерах, что объект, возвращаемый функцией инициализации в сценарии use: (как в случае с вашим кодом), имеет только update и destroy, остальные созданный экземпляр (экземпляр chart.js в вашем коде) работает сам по себе, но не раскрывается (вы можете изучить его полностью, если он работает для вас). Посмотрите, например, на первый пример в вопросе из этой темы SO.
Я вижу аналогию с моим использованием chart.js в среде vanilla html+js — в большинстве случаев мне не нужно объявлять переменную const chart = new Chart(...., достаточно просто построить экземпляр диаграммы new Chart(...., важно предоставить правильные данные инициализации, тогда он будет работать сам по себе, ссылка на него бесполезна. Что ж, в вашем случае вам нужен метод destroy (я не знаю, нужен ли на самом деле update), поэтому, возможно, ваша функция addChart может возвращать только destroy, то есть без части ...chart во второй версии
На первый взгляд кажется, что это не вызвано плагином. Кажется, в
ChartMetrics.svelteв строке 454 есть вызовdestroyдиаграммы, который делаетthisundefinedвнутри функции, что-то вродеchart.destroy.call()вместоchart.destroy()