i'm realative new to Angular, but i have some baggage from other JS Frameworks like Vue or React. Right now i'm creating an Angular Lab app in which i ask 2 APIs for information, and when this its delivered i try to refresh the child component i have included inside the parent one (child is called Main and father is called App).
My issue is, i don't really know how to update this child component template, and i'm not really finding useful information online, so its a bit of a struggle.
My execution flow: Father component has a textbox and a button --> when you write down a city and press de button 1st api is called, it delivers de coordinates of the 1st city ocurrence --> when its done, calls with thos coordinates to the second API that delivers the weather code for thats coordinates --> Those weather codes get printed in the child component.
To handle the button click i've created a Directive, this directive uses a Service to storage the values.
PD= I'm using Angular 14
Here is some code:
Directive
@Directive({
selector: '<button [showWeather]>'
})
export class ShowWeatherDirective {
constructor(private sharedService: SharingService,
private askApi: ServiceAskAPIService,
private askLocation: ServiceGetCityLocationAPIService,) { }
currentWeather = this.sharedService.weatherResults$;
@HostListener('click',['$event.target'])
onClick(btn: any){
console.log("se ha pulsado el botón", btn);
this.getCityWeather();
}
getCityWeather(){
var city =(document.getElementById("cityInput") as HTMLInputElement).value;
this.askLocation.getCityLocation(city)
.then(location=>{
this.askApi.getCityWeather(location.toString()).then(answer=>{
// after both apis have answered we process the data
console.log(answer);
console.log(answer.valueOf)
let jsonparsed = JSON.parse(answer);
let myWeeklyIntervals = jsonparsed.data.timelines[0].intervals
const weatherCodes : WeatherCodes[] = [
{
id:0,
weather:"",
img:"",
}
]
for(let res of myWeeklyIntervals){
let weathercode : WeatherCodes = {
id: 0,
weather:"",
img:""
}
console.log(res);
weathercode.id = res.values.weatherCode;
weatherCodes.push(weathercode);
}
console.log(weatherCodes)
this.sharedService.updateWeatherResults(weatherCodes);
})
});
}
}
Sharing service
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class SharingService {
private sharingObject = new Subject<any[]>();
weatherResults$ = this.sharingObject.asObservable();
constructor() { }
get sharingValue() {
return this.sharingObject
}
set sharingValue(obj) {
this.sharingObject = obj;
}
updateWeatherResults(results: any[]){
this.sharingObject.next(results);
}
}
Child component
@Component({
selector: 'component-main',
templateUrl: './main.component.html',
styleUrls: ['./main.component.css']
})
export class MainComponent {
private weatherResults =new BehaviorSubject<Object>(this.sharedService.weatherResults$);
weatherResultObservable$: Observable<Object> = this.weatherResults.asObservable();
weatherCodes: WeatherCodes[] = [
{ id: 0, weather: "Unknown", img: "" },
{ id: 1000, weather: "Clear, Sunny", img: "" },
{ id: 1100, weather: "Mostly Clear", img: "" },
{ id: 1101, weather: "Partly Cloudy", img: "" },
{ id: 1102, weather: "Mostly Cloudy", img: "" },
{ id: 1001, weather: "Cloudy", img: "" },
{ id: 2000, weather: "Fog", img: "" },
{ id: 2100, weather: "Light Fog", img: "" },
{ id: 4000, weather: "Drizzle", img: "" },
{ id: 4001, weather: "Rain", img: "" },
{ id: 4200, weather: "Light Rain", img: "" },
{ id: 4201, weather: "Heavy Rain", img: "" },
{ id: 5000, weather: "Snow", img: "" },
{ id: 5001, weather: "Flurries", img: "" },
{ id: 5100, weather: "Light Snow", img: "" },
{ id: 5101, weather: "Heavy Snow", img: "" },
{ id: 6000, weather: "Freezing Drizzle", img: "" },
{ id: 6001, weather: "Freezing Rain", img: "" },
{ id: 6200, weather: "Light Freezing Rain", img: "" },
{ id: 6201, weather: "Heavy Freezing Rain", img: "" },
{ id: 7000, weather: "Ice Pellets", img: "" },
{ id: 7101, weather: "Heavy Ice Pellets", img: "" },
{ id: 7102, weather: "Light Ice Pellets", img: "" },
{ id: 8000, weather: "Thunderstorm", img: "" }
]
currentWeather: WeatherCodes[] = [];
constructor(private sharedService: SharingService){}
}
Child component template
<p>main works!</p>
<div id="MyClass" *ngIf="weatherResultObservable$| async">
<p> {{weatherResultObservable$}}</p>
</div>
<script>
console.log("nope")
</script>
My most sincere apologize if you find anything ultrageously wrong, i'm still a learner. Thank you very much for you answers
I tried using observable as i think its mainly the resource i should be using, but i'm missing something in the "live-reload" part thats getting me really confused
i don't how i even managed to do it, but this is the answer to the issue i have, so i post iot in order to help anyone in the future that finds this:
I modified my ChildComponent (main) to subscribe to the service that stores the data on its initialization (ngOnInit()):
export class MainComponent implements OnInit{
weatherResultObservable$: Observable<any[]> | undefined;
currentWeather: WeatherCodes[] = [];
constructor(private sharedService: SharingService){}
ngOnInit(): void {
this.weatherResultObservable$ = this.sharedService.weatherResults$;
this.weatherResultObservable$.subscribe((results)=>{
this.currentWeather=results;
})
}
}
After this, i only had to update my ChildComponent Template to fit the object properly: (Note that weather.weather references a Interface i did not share with you in this example because it was not needed)
<div id="MyClass" *ngIf="weatherResultObservable$ | async">
<p *ngFor="let weather of currentWeather">{{ weather.weather }}</p>
</div>
Output: