Home > Net >  Passing data between components with ngFor not working on Angular14
Passing data between components with ngFor not working on Angular14

Time:07-15

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

<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" >
        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.

CodePudding user response:

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,
          ],
        },
      ],
    }
  }
}
  • Related