Can't pass array to chart.js which got its data from @Input

Viewed 2214

I'm trying to understand how to pass data from a parent component to a child component.
More specific, i want to hand over and array from the parent component to the child component in order to use it as a data source for a chart.

I'm using Angular 8, mdbootstrap (which uses chart.js 2.5.0). I read a bunch of tutorials and i figured out how to pass content from a parent component to a child component. I can access strings etc from within my child template using extrapolation.
My problem might be related to the way chart.js handles the rendering of its charts.
I'm not sure at which point of the lifecycle it needs its data. I tried to fill the needed variables in the ngOnInit method and the AfterViewInit method (not shown in the code), but that didn't change anything.

Parent Component (statistics.component.ts)

export class StatisticsComponent implements OnInit {

  // business logic
  public isDataLoaded = false;
  public clientNumberList: string[] = new Array();
  public clientNumberCountList: number[] = new Array();

  // chart related stufff
  public chartLabel = 'User Statistics';

  public chartOptions: any = {
    responsive: true,
    maintainAspectRatio: false,
    scales: {
      xAxes: [{
        scaleLabel: {
          display: true,
          labelString: 'Client Number'
        }
      }],
      yAxes: [{
        scaleLabel: {
          display: true,
          labelString: 'Count'
        }
      }]
    }
  };

  constructor(private sdoUserStatisticsService: SdoUserStatisticsService) {}

  ngOnInit(): void {
    // get users and counts
    this.sdoUserStatisticsService.getUserStatistics().subscribe(users => {
      for (const user of users) {
        this.clientNumberList.push(user.clientNumber);
        this.clientNumberCountList.push(user.count);
      }
      this.isDataLoaded = true;
    })
      ;
  }
}

statistics.component.html

<div *ngIf="isDataLoaded">
<app-bar-chart [chartLabelInput]="chartLabel" [dataArrayInput]="clientNumberCountList" [labelArray]="clientNumberList" [chartOptionsInput]="chartOptions"></app-bar-chart>
</div>

Child Component (bar-chart.component.ts)

export class BarChartComponent implements OnInit{

  public chartType = 'bar';

  @Input() chartLabelInput: string;
  @Input() dataArrayInput: number[];

  public chartLabel: string;
  public dataArray: number[] = this.dataArrayInput;
  public chartDatasets: Array<any> = [
    {data: this.dataArray, label: this.chartLabel}
  ];

  @Input() labelArray: string[];
  public chartLabels: Array<any> = this.labelArray;

  @Input() chartOptionsInput: any;
  public chartOptions = this.chartOptionsInput;

  constructor() {}
  public chartClicked(e: any): void { }
  public chartHovered(e: any): void { }

  ngOnInit(): void {}
}

bar-chart.component.html

<canvas mdbChart
        [chartType]="chartType"
        [datasets]= "chartDatasets"
        [labels]="chartLabels"
        [options]="chartOptions"
        [legend]=true
        (chartHover)=chartHovered($event)
        (chartClick)=chartClicked($event)>
</canvas>

I would expect that i can access the dataArrayInput in the bar-chart.component.ts and thereby give this data to the chart. In reality, i can access this array in the ngOnInit method (not shown in code), but not use it for the chart. I get the following error in the Browser Console:

ERROR TypeError: "newElm.data is undefined"
    Angular 10
        datasets
        getDatasets
        getChartBuilder
        refresh
        ngOnInit
        checkAndUpdateDirectiveInline
        checkAndUpdateNodeInline
        checkAndUpdateNode
        debugCheckAndUpdateNode
        debugCheckDirectivesFn
    View_BarChartComponent_0 BarChartComponent.html:1
    Angular 30
    RxJS 5
    Angular 9ERROR TypeError: "newElm.data is undefined"
    Angular 10
        datasets
        getDatasets
        getChartBuilder
        refresh
        ngOnInit
        checkAndUpdateDirectiveInline
        checkAndUpdateNodeInline
        checkAndUpdateNode
        debugCheckAndUpdateNode
        debugCheckDirectivesFn
    View_BarChartComponent_0 BarChartComponent.html:1
    Angular 30
    RxJS 5
    Angular 9

I hope someone can help me :)

1 Answers

I think this is an Angular lifecycle issue. Your problem is in how you are using the @Input data. You clearly want to take the data that is coming in with dataArrayInput, but you aren't accessing it correctly.

Move your assignment of the variables that depend on the @Input values to within the ngOnInit method. The value of the @Input variables is not available during construction of the component, so when you create the dependent variables, you are initializing them with undefined.

export class BarChartComponent implements OnInit {

  public chartType = 'bar';

  @Input() chartLabelInput: string;
  @Input() dataArrayInput: number[];

  public chartLabel: string;
  public dataArray: number[];
  public chartDatasets: Array < any > ;

  @Input() labelArray: string[];
  public chartLabels: Array < any > ;

  @Input() chartOptionsInput: any;
  public chartOptions;

  constructor() {}
  public chartClicked(e: any): void {}
  public chartHovered(e: any): void {}

  ngOnInit(): void {
    this.dataArray = this.dataArrayInput;
    this.chartDatasets = [{
      data: this.dataArray,
      label: this.chartLabel
    }];
    this.chartLabels = this.labelArray;
    this.chartOptions = this.chartOptionsInput;
  }
}

Take a look at this question and this question.

Related