Currently learning Angular and API calls by writing a Weather app using WeatherAPI (https://app.swaggerhub.com/apis-docs/WeatherAPI.com/WeatherAPI/1.0.2-oas3-oas3.1-oas3.1/#/)
I am writing a Dashboard component that displays the location, temperature, and weather conditions (clear, cloudy,...etc.). as well as change the associated div's background between a "night" image and a "day" image. While I managed the former, it seems that the image URL isn't being loaded, so the component's background is in default white.
I wrote a DashboardService that calls the API:
//dashboard.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { catchError, retry } from 'rxjs';
import { API } from '../const';
import { ApiCurrentReturnModel } from '../schema';
@Injectable({
providedIn: 'root'
})
export class DashboardService {
constructor(private http: HttpClient) { }
/**
*
* @param currLocation the name of the area to be queried for
* @returns current weather data of location specified
*/
getCurrent(currLocation : string) {
const url = API.URL.replace("{ call }", API.CURRENT)
.replace("{ q }", currLocation.replaceAll(" ", "%20"))
.replace("{ key }", API.KEY);
return this.http.get(url);
}
}
which returns the following (example) .json from WeatherAPI
{
"location": {
"name": "New York",
"region": "New York",
"country": "United States of America",
"lat": 40.71,
"lon": -74.01,
"tz_id": "America/New_York",
"localtime_epoch": 1658522976,
"localtime": "2022-07-22 16:49"
},
"current": {
"last_updated_epoch": 1658522700,
"last_updated": "2022-07-22 16:45",
"temp_c": 34.4,
"temp_f": 93.9,
"is_day": 1,
"condition": {
"text": "Partly cloudy",
"icon": "//cdn.weatherapi.com/weather/64x64/day/116.png",
"code": 1003
},
"wind_mph": 16.1,
"wind_kph": 25.9,
"wind_degree": 180,
"wind_dir": "S",
"pressure_mb": 1011,
"pressure_in": 29.85,
"precip_mm": 0,
"precip_in": 0,
"humidity": 31,
"cloud": 75,
"feelslike_c": 37,
"feelslike_f": 98.6,
"vis_km": 16,
"vis_miles": 9,
"uv": 8,
"gust_mph": 11.6,
"gust_kph": 18.7,
"air_quality": {
"co": 293.70001220703125,
"no2": 18.5,
"o3": 234.60000610351562,
"so2": 12,
"pm2_5": 13.600000381469727,
"pm10": 15,
"us-epa-index": 1,
"gb-defra-index": 2
}
}
}
My current plan is to utilze the is_day value in the .json to change the link to the background image. Said link is stored in a variable called currWeatherBackgroundUrl. This is done in the getCurrentWeatherBackground() function in dashboard.component.ts
//dashboard.component.ts
import { Component, OnInit } from '@angular/core';
import { DashboardService } from '../service/dashboard.service';
import { ApiCurrent, ApiCurrentReturnModel, ApiLocation } from '../schema';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css', '../app.component.css']
})
export class DashboardComponent implements OnInit{
private currentLocation: string = 'Hanoi';
private apiResult!: ApiCurrentReturnModel; //interface for reading .json data
private apiCurrent!: ApiCurrent; //child of ApiCurrentReturnModel
private apiLocation!: ApiLocation; //child of ApiCurrentReturnModel
// AN ATTEMPT AT USING A TERNARY OPERATION TO DETERMINE WHICH IMAGE TO USE AS THE DIV'S BACKGROUND
//private currWeatherBackgroundUrl: string = this.currentData.current.is_day == 1 ? '../assets/bg/daytime-image.jpg' : '../assets/bg/night-image.jpg';
private currWeatherBackgroundUrl = ''; //link init as empty
constructor(private dashboardService: DashboardService) {
//Same ternary operation attempt but in constructor instead.
//this.currWeatherBackgroundUrl = this.currentData.current.is_day == 1 ? '../assets/bg/daytime-image.jpg' : '../assets/bg/night-image.jpg';
}
//ngOnInit life cycle hook
ngOnInit(): void {
this.loadData(); //read data from json
this.getCurrentWeatherBackground(); //choose background image
window.alert("ngOnInit"); //debug alert
}
loadData() {
this.dashboardService.getCurrent(this.currentLocation).subscribe( rs => {
let result = rs as ApiCurrentReturnModel;
this.apiResult = result;
this.apiLocation = result.location;
this.apiCurrent = result.current;
}
);
}
getCurrentWeatherBackground() {
if (this.currentData.current.is_day != 1) {
//this.currWeatherBackgroundUrl = '../assets/bg/night-image.jpg';
this.setCurrWeatherBackgroundUrl('../assets/bg/night-image.jpg');
window.alert("night");
}
else {
//this.currWeatherBackgroundUrl = '../assets/bg/daytime-image.jpg';
this.setCurrWeatherBackgroundUrl('../assets/bg/daytime-image.jpg');
window.alert("day");
}
window.alert("getCurrWeatherBg");
}
get currentData() {
return this.apiResult;
}
getCurrWeatherBackgroundUrl() {
return this.currWeatherBackgroundUrl;
}
setCurrWeatherBackgroundUrl(url: string) {
this.currWeatherBackgroundUrl = url;
}
}
However, ngOnInit() is unable to execute getCurrentWeatherBackground() as indicated by the debug alert not being executed. The same can be said of the alerts within getCurrentWeatherBackgroundUrl(). As a result, the initialized variable to hold the URL remains empty.
Additionally, ApiCurrent, ApiLocation, and ApiCurrentReturnModel are interfaces that stores the .json data as follows:
export interface ApiLocation {
name: string
region: string
country: string
lat: number
lon: number
tz_id: string
localtime_epoch: number
localtime: string
}
export interface ApiCurrent {
last_updated_epoch: number
last_updated: string
temp_c: number
temp_f: number
is_day: number
condition: {
text: string
icon: string
code: number
}
wind_mph: number
wind_kph: number
wind_degree: number
wind_dir: string
pressure_mb: number
pressure_in: number
precip_mm: number
precip_in: number
humidity: number
cloud: number
feelslike_c: number
feelslike_f: number
vis_km: number
vis_miles: number
uv: number
gust_mph: number
gust_kph: number
air_quality: {
co: number
no2: number
o3: number
so2: number
pm2_5: number
pm10: number
us_epa_index: number
gb_defra_index: number
}
}
export interface ApiCurrentReturnModel {
location: any
current: any
}
I have verified that upon manually setting the URL in currWeatherBackgroundUrl to either of the links used getCurrentWeatherBackground() properly sets the background image of the div.
I've tried to use ternary operations to determine which image to use as indivated by the commented-out expressions in dashboard.component.ts.
More notably, upon removal of the getCurrentWeatherBackground() function from ngOnInit(), both loadData() and the alert is executed. Meaning the issue must be within getCurrentWeatherBackground(). I suspect it has something to with how I'm reading the .json data, as the is_day in said .json is typed as an int32. All I'm really doing in regards of reading the .json data is within loadData().
Why is it that the currWeatherBackgroundUrl isn't being changed? Why are the if-statements in getCurrentWeatherBackground() not triggering?
Sorry for the long post! I really appreciate any help and you staying with me throughout this process!