2

I would like to make a re-useable, stacked bar chart with @Input() properties in Angular. My data is a nested array.

stacked bar chart

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?

1
  • try to isolate the problem. What is undefined ? Could be this.barChartData.datasets or maybe data: this.barData[0], also add a console.log(this.barChartData) and console.log(this.defaultBarChartData) and console.log(this.barData Commented Jun 9, 2022 at 7:05

1 Answer 1

2

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.

ngOnInit()

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',
      },
    ],
  };

  ...
}

Sample StackBlitz Demo

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.