I'm trying to create simple CRUD database with Spring Boot and Angular using REST requests and draw some charts out of it. Spring boot sends this after GET request:
"name" : "COVID",
"infected": 500,
"simulationTime": 3,
"rvalue": 1.2,
"dailyStatsList": [
{
"day": 1,
"pv": 9500,
"pr": 0,
"pm": 0,
"pi": 500
},
{
"day": 2,
"pv": 9392,
"pr": 0,
"pm": 0,
"pi": 608
},
{
"day": 3,
"pv": 9260,
"pr": 0,
"pm": 0,
"pi": 740
}
]
}
This is my component.ts file:
export class SimulationDetailsComponent implements OnInit {
currentSimulation!: SimulationWithStats;
chartData = [
{ data: [10, 20, 30, 40, 50], label: 'Value1' },
{ data: [], label: 'Value2' },
{ data: [], label: 'Value3' },
];
public chartLabel: string[] = ['1', '2', '3', '4', '5'];
lineChartOptions = {
responsive: true,
};
lineChartColors: Color[] = [
{
borderColor: 'black',
backgroundColor: 'rgba(255,255,0,0.28)',
},
];
lineChartLegend = true;
lineChartPlugins = [];
lineChartType: ChartType = 'line';
constructor(
private controllerService: ControllerService,
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit(): void {
var id = this.route.snapshot.params['id'];
this.getSimulation(id);
for (let i = 0; i < 5; i ) { //THIS ONE WORKS FINE
this.chartData[1].data.push(i * 2);
}
for (let dailyStats of this.currentSimulation.dailyStatsList) { //THIS DOESN'T WORK
this.chartData[2].data.push(dailyStats.pi);
}
}
getSimulation(id: string): void {
this.controllerService.get(id).subscribe(
(data) => {
this.currentSimulation = data;
console.log(data);
},
(error) => {
console.log(error);
}
);
}
}
Unfortunately, it doesn't work. It looks like currentSimulation isn't initialized at the time I want to fill my chartData[]. I admit, that currentSimulation initalizes fine, because I can print all of the data on html page. What might be the problem? Do you think that I should wait some time before chartData[] filling?
CodePudding user response:
The problem is that you're not awaiting for the http call to return the actual data.
Change the method getSimulation
to look like this:
async getSimulation(id: string): Promise<void> {
try {
this.currentSimulation = await this.controllerService.get(id).toPromise();
console.log('current simulation data retrieved successfully', this.currentSimulation);
} catch (error) {
console.error('error retrieving current simulation', error);
}
}
And then also do this adjustments to ngOnInit()
.
async ngOnInit(): Promise<void> {
var id = this.route.snapshot.params['id'];
await this.getSimulation(id);
.............................
}
This should do the trick.
By the way, I don't know what version of angular you're using, that's why I used .toPromise()
for casting from Observable to Promise. However on the recent versions of Angular (IIRC Angular 11 ), lastValueFrom
is the one to use, since .toPromise()
was deprecated and will be removed sooner than later.
So getSimulation
would ideally look like this:
async getSimulation(id: string): Promise<void> {
try {
this.currentSimulation = await lastValueFrom(this.controllerService.get(id));
console.log('current simulation data retrieved successfully', this.currentSimulation);
} catch (error) {
console.error('error retrieving current simulation', error);
}
}