I would like to make a re-useable, stacked bar chart with Inputs in Angular. My data is a nested array.
I cannot figure out how to correctly setup my chart, I always get the error in the console: Error: Uncaught (in promise): TypeError: Cannot read property '0' of undefined TypeError: Cannot read property '0' of undefined
The sample data:
barData = [[65, 59, 80, 81, 56, 55, 40], [28, 48, 40, 19, 86, 27, 90]];
barLabels = ["2006", "2007", "2008", "2009", "2010", "2011", "2012"];
The code:
@Input() barData!: (number | ScatterDataPoint | BubbleDataPoint)[][];
@Input() barLabels!: string[];
public barChartType: ChartType = "bar";
public barChartData: ChartConfiguration["data"];
defaultBarChartData: Partial<ChartConfiguration["data"]> = {
labels: this.barLabels,
datasets: [
{
data: this.barData[0],
label: "Income",
backgroundColor: "#3ABD32"
},
{
data: this.barData[1],
label: "Expense",
backgroundColor: "#E02A45"
},
],
};
ngOnInit(): void {
if (
this.barData !== undefined &&
this.barLabels !== undefined &&
Array.isArray(this.barData) &&
this.barData.length > 0 &&
Array.isArray(this.barLabels) &&
this.barLabels.length > 0
) {
this.barChartData = {
...this.defaultBarChartData,
...{ labels: this.barLabels },
} as ChartConfiguration["data"];
this.barChartData.datasets[0].data = this.barData[0];
} else {
throw new Error("Charts must have their data and labels inputs defined.");
}
}
public barChartOptions: ChartConfiguration["options"] = {...}
Its template:
<canvas
baseChart
[data]="barChartData"
[options]="barChartOptions"
[type]="barChartType">
</canvas>
Could someone help me find the error in my setup, please?
CodePudding user response:
Move the initializing value to defaultBarChartData
logic to ngOnInit
method.
From Angular - Input,
Decorator that marks a class field as an input property and supplies configuration metadata. The input property is bound to a DOM property in the template. During change detection, Angular automatically updates the data property with the DOM property's value.
To guarantee the variables with @Input()
decorator are updated with value, thus the ngOnInit
is needed.
Initialize the directive or component after Angular first displays the data-bound properties and sets the directive or component's input properties.
defaultBarChartData: Partial<ChartConfiguration['data']>;
ngOnInit(): void {
this.defaultBarChartData = {
labels: this.barLabels,
datasets: [
{
data: this.barData[0],
label: 'Income',
backgroundColor: '#3ABD32',
},
{
data: this.barData[1],
label: 'Expense',
backgroundColor: '#E02A45',
},
],
};
...
}