Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Passing data between components with ngFor not working on Angular14

I am working on a personal project where I want to register every meal I eat along the day, and display them using charts.

I already know how to pass data between components using Input() between parent and child, but my problem here is slightly different. I provide the code and then explain what is my problem.

today.component.html

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

<div *ngIf="loaded">
        <div *ngFor="let meal of mealList">
          <h1>{{ meal.name }}</h1>
          <app-chart
            [numCalories]="meal.calories"
            [numCarbs]="meal.carbs"
            [numFat]="meal.fat"
            [numProtein]="meal.protein"
          >
          </app-chart>
        </div>
      </div>

      <div *ngIf="!loaded" class="alert alert-info">
        Loading data...
      </div>

today.component.ts

export class TodayComponent implements OnInit {
  mealList: Meal[] = [];
  loaded: boolean = false;

  constructor(private mealService: MealService, private router: Router, private toastr: ToastrService) { }

  ngOnInit(): void {
    this.getMeals();
  }
  
  getMeals() {
    this.mealService.getMeals().subscribe((meals) => {
      this.mealList = meals;
    });
    this.loaded = true;
  }   
 }

chart.component.html

<div>
  <div>
    <div style="display: block">
      <div>
        <canvas baseChart [data]="doughnutChartData" [type]="doughnutChartType">
        </canvas>
      </div>
    </div>
  </div>
</div>

chart.component.ts

export class ChartComponent {
  @Input() numCalories!: number;
  @Input() numFat!: number;
  @Input() numCarbs!: number;
  @Input() numProtein!: number;

  constructor() {}

  public doughnutChartLabels: string[] = [
    'Calories',
    'Proteins',
    'Carbs',
    'Fat',
  ];
  public doughnutChartData: ChartData<'doughnut'> = {
    labels: this.doughnutChartLabels,
    datasets: [
      {
        data: [
          this.numCalories,
          this.numFat,
          this.numCarbs,
          this.numProtein,
        ],
      },
    ],
  };
  public doughnutChartType: ChartType = 'doughnut';
}

I know the data is loading correctly because, in the HTML layout of today’s component, where I use {{ meal.name }}, I am referring to the time when you eat, for example dinner, lunch, and it loads fine, so my problem is passing the other data to the chart component.

Since I am assigning the data I want to pass with an NgFor, I do not have that variable in the parent component, and that is how it is made in every example I have seen, and it seems I need to do something else, but I do not really know what to do.

>Solution :

You’ve to set doughnutChartData within ngOnInit.

Keep in mind that a directive’s data-bound input properties are not set until after construction.

export class ChartComponent implements OnInit {
  @Input() numCalories!: number;
  @Input() numFat!: number;
  @Input() numCarbs!: number;
  @Input() numProtein!: number;

  public doughnutChartData: ChartData<'doughnut'> = null;
  public doughnutChartLabels: string[] = [
    'Calories',
    'Proteins',
    'Carbs',
    'Fat',
  ];
  public doughnutChartType: ChartType = 'doughnut';

  constructor() {}

  ngOnInit() {
    this.doughnutChartData = {
      labels: this.doughnutChartLabels,
      datasets: [
        {
          data: [
            this.numCalories,
            this.numFat,
            this.numCarbs,
            this.numProtein,
          ],
        },
      ],
    }
  }
}

or through a single Input of type Meal, as advised by @penleychan

export class ChartComponent implements OnInit {
  @Input() meal!: Meal;

  public doughnutChartData: ChartData<'doughnut'> = null;
  public doughnutChartLabels: string[] = [
    'Calories',
    'Proteins',
    'Carbs',
    'Fat',
  ];
  public doughnutChartType: ChartType = 'doughnut';

  constructor() {}

  ngOnInit() {
    this.doughnutChartData = {
      labels: this.doughnutChartLabels,
      datasets: [
        {
          data: [
            this.meal.numCalories,
            this.meal.numFat,
            this.meal.numCarbs,
            this.meal.numProtein,
          ],
        },
      ],
    }
  }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading