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