3

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 :)

EyedPeas
  • 146
  • 4
  • 17
  • Possible duplicate of [How to update the data from parent to child data passing](https://stackoverflow.com/questions/56561697/how-to-update-the-data-from-parent-to-child-data-passing) – Ben Racicot Jun 12 '19 at 13:11
  • @BenRacicot I read that Question and Answer before i posted my question. It helped me to understand the problem in general. But the Problem with the chart.js part remains. – EyedPeas Jun 12 '19 at 13:16
  • Gotcha, is the array in parent looking correct before it's sent anywhere? I would replicate this in StackBlitz for both of our benefits. – Ben Racicot Jun 12 '19 at 13:20
  • Yes, if I print the content of the array in the parent component and the child component to the console, they are identical. Okay, I'll try to replicate the problem in stackblitz – EyedPeas Jun 12 '19 at 13:27
  • Ok, so you may want to change the title of the question so it's not a dup and maybe more specific to chart.js and Angular. Hey, what is `newElm`? that's not in your code and the problem lies there. – Ben Racicot Jun 12 '19 at 13:37
  • The `newElm` is from `angular-bootstrap-md.js`. For some reason, the array i pass to the chart (`chartDatasets`) is undefined. – EyedPeas Jun 12 '19 at 13:42
  • I figured out my solution. It was related to the way I wanted to access the `@Input` variables as described by @Rich down below. @Ben Racicot: Thank you very much for your time and effort :) – EyedPeas Jun 12 '19 at 14:26

1 Answers1

2

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.

Rich
  • 1,567
  • 14
  • 24
  • Awesome! That removed the error about the undefined fields! Thank you! Now my problem is: The chart options variable is of type Object. I can't access its content. Do i have to do something with it? – EyedPeas Jun 12 '19 at 13:48
  • You should be able to... I see you declaring it in `statistics.component.ts`, so it doesn't appear syntactically invalid. It should be a simple matter of doing `chartOptions.responsive` or whaterver. Maybe it's a configuration problem with chart.js? idk – Rich Jun 12 '19 at 13:54
  • Ok, i figured it out. I had to move the `div` around the `` to the child template. Thank you very much for your help! – EyedPeas Jun 12 '19 at 14:24