2
votes

How pass data from one component to other one in Angular 6? I created service (weather.service), weather.component, interface and app.component. So, I have data from weather api in weather.component but I want to pass data to app.component and use it to change background-images dynamically. current-weather.component

import {Component, OnInit} from '@angular/core';
import {ICurrentWeather} from '../icurrent-weather';
import {WeatherService} from '../weather/weather.service';

@Component({
 selector: 'app-current-weather',
 templateUrl: './current-weather.component.html',
 styleUrls: ['./current-weather.component.css']
})
export class CurrentWeatherComponent implements OnInit {

current: ICurrentWeather;

constructor(public weatherService: WeatherService) {
this.current = {
  city: '',
  country: '',
  image: '',
  temperature: 80,
  description: '',
  natural: '',
  bgImage: '',
  visibility: 12478,
  weatherId: 200,
} as ICurrentWeather;


}

ngOnInit() {
this.weatherService.getCurrentWeather('Seattle', 'US')
  .subscribe((data) => this.current = data);

}

}

app.component

import {Component} from '@angular/core';
import {ICurrentWeather} from './icurrent-weather';


@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrls: ['./app.component.css']
})
export class AppComponent {

 weatherID: ICurrentWeather;
 bgImage: string;

 constructor() {

  if ( this.weatherID.weatherId > 800) {
    this.bgImage = '../../../assets/images/cloud.jpg';
  } else if (this.weatherID.weatherId === 800) {
    this.bgImage = '../../../assets/images/clear.jpg';
  } else if (this.weatherID.weatherId >= 700) {
    this.bgImage = '../../../assets/images/fog.png';
  } else if (this.weatherID.weatherId >= 600) {
    this.bgImage = '../../../assets/images/snow.png';
  } else if (this.weatherID.weatherId >= 500) {
    this.bgImage = '../../../assets/images/rain.png';
  } else if (this.weatherID.weatherId >= 300) {
    this.bgImage = '../../../assets/images/drizzly.png';
  } else {
    this.bgImage = '../../../assets/images/thunderstorm.jpg';
  }
 }
}

interface

export interface ICurrentWeather {
 city: string;
 country: string;
 image: string;
 temperature: number;
 description: string;
 natural: string;
 weatherId: number;
 visibility: number;
}

weather.service

import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {environment} from '../../environments/environment';
import {Observable} from 'rxjs';
import {ICurrentWeather} from '../icurrent-weather';
import {map} from 'rxjs/internal/operators';

interface ICurrentWeatherData {
  weather: [{
   main: string, // main:'Rain'
   description: string,
   icon: string,
   id: number,
 }];
main: {
  temp: number
};
visibility: number;  // visibility: 12874
sys: {
  country: string
};
name: string;
}

@Injectable({ providedIn: 'root' }) export class WeatherService {

 constructor(private http: HttpClient) { }

 getCurrentWeather(city: string, country: string): 
  Observable<ICurrentWeather> {
   return this.http.get<ICurrentWeatherData>(
    `http://api.openweathermap.org/data/2.5/weather? 
      q=${city},${country}&APPID=${environment.apiID}`
      ).pipe(
       map(data => this.transformToICurrentWeather(data))
     );
   }


   private transformToICurrentWeather(data: ICurrentWeatherData): 
    ICurrentWeather {
     return {
      city: data.name,
      country: data.sys.country,
      image: `http://openweathermap.org/img/w/${data.weather[0].icon}.png`,
      temperature: this.convertKelvinToFahrenheit(data.main.temp),
      description: data.weather[0].description,
      natural: data.weather[0].main,
      weatherId: data.weather[0].id,
      visibility: data.visibility,
     };
   }
  private convertKelvinToFahrenheit(kelvin: number): number {
    return kelvin * 9 / 5 - 459.67;
   }
}

Please, any suggestions?

2

2 Answers

1
votes

you need an @Output to send to the parent component. here is how you will pass it up. also you should take the weatherId checks out of the constructor and put it in the ngOnInit

current-weather.component.ts

@Output() weatherId: EventEmitter<boolean> = new EventEmitter();

ngOnInit() {
this.weatherService.getCurrentWeather('Seattle', 'US')
  .subscribe((data) => {
      this.current = data;
      this.weatherId.emit(data.weatherId);
    });

}

app.component.html

<app-current-weather (weatherId)="updateWeatherId($event)"></app-current-weather>

app.component.ts

ngOnInit() {
   this.updateWeatherId(this.weatherID.weatherId);
}

updateWeatherId(weatherId) {
   if ( weatherId > 800) {
      this.bgImage = '../../../assets/images/cloud.jpg';
    } else if (weatherId === 800) {
      this.bgImage = '../../../assets/images/clear.jpg';
    } else if (weatherId >= 700) {
      this.bgImage = '../../../assets/images/fog.png';
    } else if (weatherId >= 600) {
      this.bgImage = '../../../assets/images/snow.png';
    } else if (weatherId >= 500) {
      this.bgImage = '../../../assets/images/rain.png';
    } else if (weatherId >= 300) {
      this.bgImage = '../../../assets/images/drizzly.png';
    } else {
      this.bgImage = '../../../assets/images/thunderstorm.jpg';
    }
  }
}
2
votes

Since CurrentWeatherComponent will be a direct child of AppComponent (I assume), the child can inject the parent in the constructor and from there, reach the parent when it needs to change image. Something like this:

import {Component, OnInit} from '@angular/core';
import {ICurrentWeather} from '../icurrent-weather';
import {WeatherService} from '../weather/weather.service';
import {AppComponent} from '../../app.component'; // change path if incorrect

@Component({
  selector: 'app-current-weather',
  templateUrl: './current-weather.component.html',
  styleUrls: ['./current-weather.component.css']
})
export class CurrentWeatherComponent implements OnInit {

  current: ICurrentWeather;

  // inject weather service and parent component
  constructor(public weatherService: WeatherService, private parent: AppComponent) { }

  ngOnInit() {
    this.current = {
      city: '',
      country: '',
      image: '',
      temperature: 80,
      description: '',
      natural: '',
      bgImage: '',
      visibility: 12478,
      weatherId: 200,
    } as ICurrentWeather;

    this.weatherService.getCurrentWeather('Seattle', 'US')
      .subscribe((data) => {
        this.current = data;
        this.parent.changeImage(data);  // call some function in parent to swap image
      });

  }

}