Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] TypeError: Cannot read property of '_meta' of undefined #4978

Closed
8 opened this issue Nov 21, 2017 · 17 comments · Fixed by #7467
Closed

[BUG] TypeError: Cannot read property of '_meta' of undefined #4978

8 opened this issue Nov 21, 2017 · 17 comments · Fixed by #7467

Comments

@8
Copy link

8 commented Nov 21, 2017

Expected Behavior

No error occurs.

Current Behavior

A linear chart is continuously updated every couple of seconds by assigning to it's datasets and labels property before calling the update method using the following code:

const chartData = chart.data as LinearChartData;
chartData.datasets = newData;
chartData.labels = labels;
chart.update(0);

After some hours of normal behavior an exception occurs in production:

TypeError: Cannot read property '_meta' of undefined
    at t.getDatasetMeta (https://localhost/vendor.bundle.js:1:236168)
    at t.updateHoverStyle (https://localhost/vendor.bundle.js:1:237714)
    at t.handleEvent (https://localhost/vendor.bundle.js:1:238496)
    at t.eventHandler (https://localhost/vendor.bundle.js:1:237904)
    at n (https://localhost/vendor.bundle.js:1:237275)
    at HTMLCanvasElement.s.(anonymous function) (https://localhost/vendor.bundle.js:1:170105)
    at e.invokeTask (https://localhost/polyfills.bundle.js:1:41200)
    at Object.onInvokeTask (https://localhost/vendor.bundle.js:1:45060)
    at e.invokeTask (https://localhost/polyfills.bundle.js:1:41121)
    at r.runTask (https://localhost/polyfills.bundle.js:1:36376) 

The stack trace points toward a bug inside Chart.js.

Possible Solution

Unknown.

Steps to Reproduce (for bugs)

I was unable to reproduce it in a development environment, it only happends sporadically in production after hours of usage.

Context

The chart is used inside a monitoring application based on angular and contiuously updated.
It looks like an uncaught exception inside of Chart.js, which is crashing the application.

Environment

  • Chart.js version: 2.6.0
  • Browser name and version: 62.0.3202.94
  • Angular Wrapper: ng2-charts 1.6.0
@Enishowk
Copy link

Enishowk commented Nov 22, 2017

What is the content of your newData ?
The problem is here, i think.

@jcopperfield
Copy link
Contributor

@Enishowk is right. Your newData probably contains an undefined entry. Try filtering your data before adding it to the Chart.

var newData = [{data: [1,2,3], label: 'data-label'}, null, 1, 'abc', undefined];
newData = newData.filter(function(val) {
	return val !== undefined
		&& val !== null
		&& typeof val === 'object'
		&& val.hasOwnProperty('data');
});
>>> newData = [{data: [1,2,3], label: 'data-label'}]

@simonbrunel
Copy link
Member

@8 did you fix it? If not, can you post a jsfiddle that reproduces this issue?

@heyrex
Copy link

heyrex commented Feb 2, 2018

I was able to produce a similar error message by passing a plot point with the y axis value set to undefined:

var plotPoints = []
for(var i = 0; i < 100; i++){
   plotPoints.push({
         x: 1,
         y: undefined
      });
}

Yields: "TypeError: can't assign to property "_meta" on "1000": not an object"

I think that ChartJS should produce a sensible error message in this case. Maybe an exception: Invalid input data type: 'undefined'?

@tharunsikhinam
Copy link

tharunsikhinam commented Dec 2, 2018

I was able to fix it by adding the following line in node_modules/chart.js/src/core/core.controller.js

`
getDatasetMeta: function(datasetIndex) {

		var me = this;

		var dataset = me.data.datasets[datasetIndex];
         //Start
		if(dataset===undefined)
			dataset={}
        //End
		if (!dataset._meta) {
			dataset._meta = {};
		}`

@jwedel
Copy link

jwedel commented Jun 4, 2019

We're also seeing this issue. We are doing a lot of changes regarding axes, labels and dataset together with chart animation. I'v read that between options and data changes, you need to update the chart, so I did this. Furthermore, before each update I did this

        this.chart.data.datasets = this.chart.data.datasets.filter(dataset => !!dataset);

        this.chart.update(5000, ChartControl.GRAPH_CHANGE_ANIMATION_LAZY);

I've also printed out a console error if a dataset is null or undefined before updating which never happens.

This is not 100% reproducible. I've now written an automated E2E test which artificially increased animation time (5s), even in that case, I can only reproce it in 50% of the test runs.

@nagix
Copy link
Contributor

nagix commented Jun 7, 2019

I could reproduce this issue with Chart.js 2.6.0 and 2.7.0. Visit https://jsfiddle.net/nagix/hmkftj7L/, hover over the top left point in blue and wait for 5 seconds. After the blue line disappears, you will see this error if you move your pointer. This issue was already fixed in #4840, and the fix is included in 2.7.1. Looking at the stack trace, this happened in an event loop, so it seems to me that these are the same issue.

@jwedel What version are you using? Can you share the stack trace of the error?

@jwedel
Copy link

jwedel commented Jun 11, 2019

@nagix We're using 2.7.3 and recently switched to 2.8.0.

This is the stack trace:

ERROR: (match)  : http://localhost:8080/js/commons.bundle.js 268385:23 "TypeError: Cannot read property '_meta' of undefined
    at Chart.getDatasetMeta (http://localhost:8080/js/commons.bundle.js:317019:16)
    at Chart.isDatasetVisible (http://localhost:8080/js/commons.bundle.js:317050:19)
    at ChartElement.\u003Canonymous> (http://localhost:8080/js/commons.bundle.js:419686:44)
    at Array.map (\u003Canonymous>)
    at ChartElement.generateLabels (http://localhost:8080/js/commons.bundle.js:419682:75)
    at Object.callback (http://localhost:8080/js/commons.bundle.js:309769:14)
    at ChartElement.buildLabels (http://localhost:8080/js/commons.bundle.js:321870:31)
    at ChartElement.update (http://localhost:8080/js/commons.bundle.js:321817:6)
    at getMinimumBoxSize (http://localhost:8080/js/commons.bundle.js:314359:19)
    at Object.each (http://localhost:8080/js/commons.bundle.js:309792:9)"

This issue was caused after calling Chart.update() and not by hovering although we're also seeing different issues in the onHover code.
We fixed this by adding "more" update calls. Since we have user configurable charts, on most updates, we need to do alot of changes to the chart config as well as the datasets. We tried to reduce the number of animated updates by calling update after consecutive config changes once and then after consecutive dataset changes. Eventually, we added update calls with lazy flag true after every single change.

From the docs it's not 100% clear if stacked changes can be done with a single update afterwards or not.

@manisharpatil
Copy link

How can we update getDatasetMeta: function(datasetIndex) method in chart.js?

@Rahul-RB
Copy link

So I got this error due to a misunderstanding while using ChartJS within ReactJS itself (not the react-chartjs-2 library):

  • If you are using Chart.js via ReactJS (not the react-chartjs-2 lib) AND you have kept the chart objects within the component state, then ensure that any function to update the data is present within the component class.

  • Eg:
    Say we have a component called "Dummy" as follows:

import React,{ Component } from "react";

let updateData = (chart,label,data) => {
	// THIS IS WRONG.
	// DON'T USE THIS.
}

class Dummy extends Component{
	constructor(...args){
		super(...args);
		this.state = {
			chartRef:new Chart(document.getElementById("chart"),{
				//options here
			})
		}
	}

	innerUpdateData = (chart,label,data) => {
		// THIS IS RIGHT.
		// USE THIS.
	}

	componentDidMount(){
		updateData(this.state.chartRef,"someLabel",[1,2,3]) // THIS CAUSES THE _meta ERROR, DON'T USE THIS.
		this.innerUpdateData(this.state.chartRef,"someLabel",[1,2,3]); // USE THIS.
	}

	render(){
		return (
			<div
				style = {{
					marginTop:"70px"
				}}
			>
				<canvas
					id="chart"
				>
				</canvas>
			</div>
		);
	}
}

export default Dummy;

@mashaod
Copy link

mashaod commented Nov 7, 2019

I also sow this issue.
Try don't use 'filter' for data of the chart. Replace 'filter' to 'map' and add 'hidden: true'.
const datasets = data.map(d => ({ ...data, hidden: !d.active }));

@ammoradi
Copy link

@mashaod 's solution solved the issue in my case.

@harshil-darji
Copy link

I am facing the same issue when I pass an onClick event to legend. This is what I have done for one of my charts within my class. Can someone help?

legend:
{
   onClick: function(e, legentdItem){
      self.newLegendClickHandler(e, legentdItem)
   }
}

The name of my chart is myChart.

  async newLegendClickHandler(e, legendItem) {

    var index = legendItem.datasetIndex;
    var ci = this.myChart;

    console.log(this.myChart);    // Getting the chart here successfuly

    var meta = ci.getDatasetMeta(index);          // Error here...

    meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;

    ci.update();
  };

@etimberg
Copy link
Member

Still happening in the latest code from master https://jsfiddle.net/4kmw3spf/1/

@hitanshiMehta-Dev
Copy link

I was able to fix it by adding the following line in node_modules/chart.js/src/core/core.controller.js

` getDatasetMeta: function(datasetIndex) {

		var me = this;

		var dataset = me.data.datasets[datasetIndex];
         //Start
		if(dataset===undefined)
			dataset={}
        //End
		if (!dataset._meta) {
			dataset._meta = {};
		}`

But you will lose once send to QA or prod or if npm version is updated.

@kadifu
Copy link

kadifu commented Apr 15, 2022

I am facing the same issue when I pass an onClick event to legend. This is what I have done for one of my charts within my class. Can someone help?

legend:
{
   onClick: function(e, legentdItem){
      self.newLegendClickHandler(e, legentdItem)
   }
}

The name of my chart is myChart.

  async newLegendClickHandler(e, legendItem) {

    var index = legendItem.datasetIndex;
    var ci = this.myChart;

    console.log(this.myChart);    // Getting the chart here successfuly

    var meta = ci.getDatasetMeta(index);          // Error here...

    meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;

    ci.update();
  };

hello, has your problem been solved, I have the same problem as you

@akbaig
Copy link

akbaig commented Jun 10, 2022

I also sow this issue. Try don't use 'filter' for data of the chart. Replace 'filter' to 'map' and add 'hidden: true'. const datasets = data.map(d => ({ ...data, hidden: !d.active }));

@mashaod's answer worked magically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.