0

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?

3
  • Of course it currentSimulation is too late, it has to wait for API call. Without knowing what you use to display chart it's difficult to help you. Commented Nov 14, 2021 at 20:27
  • I'm using Chart.js. How can I wait for an API request to be done? Is there any particular approach I should use or just wait like 1000ms? Commented Nov 14, 2021 at 20:36
  • 1
    Does this answer your question? create Chart.js after getting data from api Commented Nov 14, 2021 at 20:46

1 Answer 1

0

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);
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

May be personal opinion, but don't use promises in Angular, at least not with API calls.
That worked, thank you!
@BojanKogoj We're kind of on the same page here, but IMHO there are cases where you still want to go with promises. Not everything should end up in a subscribe. How I personally prefer to work with data in Angular goes like this: if I need the data for a subsequent call inside the class, then I try to cast it to a promise so that I can await on it in an inline manner. If I need it only in the template file (html), then I leave it as an Observable and use it with the async pipe. When I need to do a manual subscribe in .ts, I use something like subsink for easily unsubscribing in one shot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.