Search code examples
angularangular-servicesangular-httpclient

Angular service method execution order


I'm new in Angular and now trying to learn it and have a problem. I have a simple service method which I call in another component. But I have strange order of execution:

enter image description here

You can see it in console browser:

enter image description here

Could anyone please explain how does it work? And how to fix it?


Solution

  • This has to do with the fact, that I/O operations are usually designed to be non-blocking. Setting up a request via http.get is such a non-blocking operation. It takes time to complete and in the meanwhile your other code will run first.

    You wouldn't want your app to freeze while it waits for a 5sec response from the server would you?

    If you would like to display your result you may just split up your logic for that, like so:

    _weatherForecast: WeatherForecast = null;
    
    calculateWeatherForecast() {
      this.http.get<WeatherForecast>(this._url).subscribe((data) => {
          this._weatherForecast = data;
      });
    }
    
    getWeatherForecast() {
        return this._weatherForecast;
    }
    

    That way you may fetch your data independently from displaying them. Angular would detect the change of your variable and render the result. In your template you would just do:

    <div>{{getWeatherForecast()}}</div>
    

    That has the advantage that you won't fetch new data from the server, every time you want to display your weatherForecast. It gives you more control over how often and when to ask your server for new data.

    Edit:

    As it was pointed out in the comments, the code will break, when trying to access a property (in that case summary) on _weatherForecast. If you would like to avoid that you have two options:

    1. Change your template to:
    <div>{{ getWeatherForecast()?.summary }}</div>
    
    1. Change the logic in your component to:
    getWeatherForecast() {
        if(this._weatherForecast) {
            return this._weatherForecast.summary;
        }
    }
    

    You may also change the method getWeatherForecast() to get weatherForecast(). That way you may access it in your template like a property of your component, like so:

    <div>{{ weatherForecast?.summary }}</div>