Loreno Loreno - 2 months ago 19
Javascript Question

Can't get weather data from API using angular components

I want to create a simple weather app using angular 2, just to learn this framework.

I've got GraphsComponent, where I'm going to draw temperature chart.

import { Component, OnInit } from '@angular/core';

import { WeatherAPIService } from './weatherAPI.service';

@Component({

selector: 'my-graphs',

template: '<h1>Charts for {{this.weatherAPIService.cityName}}</h1>',

providers: [WeatherAPIService]
})

export class GraphsComponent implements OnInit {

weatherData = {};
cityName: string = "";


constructor(
private weatherAPIService: WeatherAPIService,
) { }

ngOnInit(): void {
this.weatherAPIService.getWeather("London").then(data => this.weatherData = data);
console.log(this.weatherData); //wrong data
}

}


I also have a WeatherAPIService, which provides weather data:

import { Injectable } from '@angular/core';


@Injectable()
export class WeatherAPIService {

weatherData = {};
cityName: string = "";

getWeatherHelper (city: string) {
var locationData = new Object();
$.get("https://maps.googleapis.com/maps/api/geocode/json?address=" + city, function (data) {

locationData['latitude'] = data.results[0].geometry.location.lat; //latitude
locationData['longitude'] = data.results[0].geometry.location.lng; //longitude

$.ajax({
url: "https://api.darksky.net/forecast/[MyAPIKey]/" + locationData['latitude'] + ',' + locationData['longitude'],
dataType: "jsonp",
success: function (data) {
//alert("The temperatute in " + city + " is " + data.currently.temperature);
this.weatherData = data;
this.cityName = city;
console.log(data); //good data
return data;
}

});

}
}

getWeather(city: string): Promise<string[]> {
return Promise.resolve(this.getWeatherHelper(city));
}

}


I want to get weather data to display it.

In getWeatherFunction, I use 2 APIs:
- Google geocoding to get latitude and longitude of the city i want weather for
- DarkSky to get the weather (it requires latitude and longitude)

The problem is the fact, that getting location and weather from APIs is asynchronous, so getWeatherHelper() finishes before the data is returned.

That's why I added weatherData and cityName in WeatherAPIService, but even though these variables have proper data after data from APIs is returned, cityName is not displayed in the template of GraphsComponent. Why is that? How should situations like this be handled? Where should I actually store the information from weather API? In the component or in the service?

As you can see, I used promise, because I thought it would get me the data after it is collected form API, but it doesn't.

As you probably noticed, I'm really new to angular, so please try to answer in the way, that I could understand it.
I know as much as I learned from official angular 2 tutorial ("Tour of heroes").

Answer

Apart from you mixing in jQuery, you're losing the this context, when using function. I'd suggest using a lambda expression, which preserves said context, so you can actually save the data.

So instead of using

function (data) {

start using a lambda, wherever you need an inline function:

(data) => {

Applied to your code:

getWeatherHelper (city: string) {
  var locationData = new Object();
    $.get("https://maps.googleapis.com/maps/api/geocode/json?address=" + city, (data) => {

       locationData['latitude'] = data.results[0].geometry.location.lat;  //latitude
       locationData['longitude'] = data.results[0].geometry.location.lng;  //longitude

        $.ajax({
            url: "https://api.darksky.net/forecast/[MyAPIKey]/" + locationData['latitude'] + ',' + locationData['longitude'],
            dataType: "jsonp",
            success: (data) => {
                //alert("The temperatute in " + city + " is " + data.currently.temperature);
                this.weatherData = data;
                this.cityName = city;
                console.log(data);  //good data
                return data;
            }

        });

    });
}
Comments