1

I'm new to asynchronous processes and I don't understand why my current method of trying to store a response from a fetch request to an api is not working.

I'm building and Angular app, where I have a api.service.ts file where I define my fetch functions. When I utilize these functions in a component and attempt to set a variable using the response, within the function call I am able to access the response, but outside it's like I never set the variable value.

My api.service.ts file currently:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class ApiService {
  API_Key = 'cf002751564a4c78f5f7ed479f1b9ba3';

public getWeatherCity(city_name) {
    return new Promise((resolve, reject) => {
      fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city_name}&appid=${this.API_Key}`)
        .then(response => {
          return response.json();
        }).then(data_fetched => {
          let data = data_fetched.results;
          resolve(data);
        })
    })
};

constructor(private http: HttpClient) { }
}

however I've also tried

public getWeatherCity(city_name) {
return this.http.get(`https://api.openweathermap.org/data/2.5/weather?q=${city_name}&appid=${this.API_Key}`);
}

the component.ts in which I attempt to use api.service:


import { Component, OnInit } from '@angular/core';
import { ApiService } from '../../api.service';
import { SearchComponent } from '../search.component';
import { FormBuilder } from '@angular/forms';



@Component({
  selector: 'app-city',
  templateUrl: './city.component.html',
  styleUrls: ['./city.component.css']
})
export class CityComponent implements OnInit {
  cityName;
  displayResults = false;
  weather;
  weatherLocation;

  constructor(private apiService: ApiService) { }

  ngOnInit(): void {
    this.cityName = "Cleveland";
    this.apiService.getWeatherCity(this.cityName).then(data => {
      this.weather = data
      this.weatherLocation = data['name'];
      console.log(this.weather);
    })
    console.log(this.weather);
    console.log(this.weatherLocation);
  }

 
}

I would expect to get results for the first and second console.log(this.weather), however I get results for the first (within the fetch function) but the second returns undefined (outside the fetch function). I'm not sure what I don't understand about asynchronous functions here. Surely there must be a way to store the response so it is accessible outside the function.

I do realize I could modify my html within the getWeatherCity function, but that seems like a messy and unpreferable solution.

Any help would be greatly appreciated.

2 Answers2

0

Your second and third console.logs happen before your apiService.getWeatherCity() returns. It's asynchronous, so it does not block execution. The service request gets fired, and the next line is hit immediately. And the next. At some point, the service call returns, and your .then() method runs.

FunkMonkey33
  • 613
  • 6
  • 17
0

If you are going to use http.get then you need to subscribe to the stream, because http.get returns an Observable:

  public getWeatherCity(city_name) {
    return this.http.get(
      `https://api.openweathermap.org/data/2.5/weather?q=${city_name}&appid=${
        this.API_Key
      }`
    );
  }

// ....

  ngOnInit(): void {
    this.cityName = "Cleveland";
    this.subscription = this.apiService
      .getWeatherCity(this.cityName)
      .subscribe(data => {
        this.weather = data;
        this.weatherLocation = data["name"];
        console.log(this.weather);
        console.log(this.weatherLocation);
      });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

https://stackblitz.com/edit/angular-ivy-bzcnj2?file=src%2Fapp%2Fapp.component.ts

Rachid Oussanaa
  • 10,348
  • 14
  • 54
  • 83
  • This still returns undefined for the second and third console.log's. – docphilstone Jan 31 '21 at 01:39
  • I updated the answer, the console logs should be inside the subscribe, because of async nature of streams – Rachid Oussanaa Jan 31 '21 at 01:53
  • I didn't pay attention to the console.logs initially – Rachid Oussanaa Jan 31 '21 at 01:54
  • So is there any way for me to change HTML or variables outside of the function? I currently have this which works, but seems incredibly clunky: ```this.apiService.getWeatherCity(this.cityName) .subscribe(data => { const weather = this.apiService.weatherReport(data) const div = document.getElementById("weather"); div.innerHTML = `
    • ${weather['location']}
    • ${weather['fahrenheit']} *F
    ` } ) ```
    – docphilstone Jan 31 '21 at 19:16