Weather App Using Angular (original) (raw)

Last Updated : 29 Aug, 2024

**We will be creating a weather application using the Angular framework. This app will allow users to check the current weather conditions by entering a city name. It will provide detailed information including temperature, weather description, wind speed, and humidity. With responsive design and interactive features, the app will offer a user-friendly experience across various devices.

**Project Preview

Screenshot-2024-08-23-at-10-03-17-InterpolationExample

Project Preview

Prerequisites

Approach

Steps to Create Weather App using Angular

**Step 1: Install Angular CLI

If you haven’t installed Angular CLI yet, install it using the following command

npm install -g @angular/cli

**Step 2: Create a New Angular Project

ng new weather-app --no-standalone
cd weather-app

**Step 3: Create a Component

Create a component. You can generate a component using the Angular CLI:

ng generate component weather-app

**Step 4: Install dependencies

Install moment library for real-time date fetching:

ng install moment --save

**Dependencies

"dependencies": {
"@angular/animations": "^18.2.1",
"@angular/common": "^18.2.1",
"@angular/compiler": "^18.2.1",
"@angular/core": "^18.2.1",
"@angular/forms": "^18.2.1",
"@angular/platform-browser": "^18.2.1",
"@angular/platform-browser-dynamic": "^18.2.1",
"@angular/router": "^18.2.1",
"moment": "^2.30.1",
"rxjs": "7.8.0",
"tslib": "^2.3.0",
"zone.js": "
0.14.10"
}

Folder Structure

PS

Folder Structure

**Example: Create the required files as seen in the folder structure and add the following codes.

**Weather Component

Below mentioned is Weather Component having HTML, CSS and JavaScript code having an input field to add state name and a Get Weather Button to show the weather update along with humidity and wind speed.

HTML `

GeeksforGeeks

Weather App Using Angular

Get Weather
    <div *ngIf="loading" class="loading">
        Loading...
    </div>

    <div *ngIf="error" class="error-message">
        {{ error }}
    </div>

    <div *ngIf="weatherData" class="animate__animated animate__fadeIn" id="weather-info">
        <h3 id="city-name">{{ weatherData.name }}</h3>
        <p id="date">{{ currentDate }}</p>
        <img [src]="iconUrl" alt="Weather Icon" id="weather-icon">
        <p id="temperature">{{ weatherData.main.temp }}°C</p>
        <p id="description">{{ weatherData.weather[0].description }}</p>
        <p id="humidity">Humidity: {{ weatherData.main.humidity }}%</p>
        <p id="wind-speed">Wind Speed: {{ weatherData.wind.speed }} m/s</p>
    </div>
</div>

CSS

/weather-app.component.css/

body { margin: 0; font-family: 'Montserrat', sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; background: linear-gradient(to right, #4CAF50, #2196F3); }

.container { text-align: center; display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 20px; }

.weather-card { background-color: rgba(255, 255, 255, 0.95); border-radius: 20px; border: 2px solid #f44336; padding: 30px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); transition: transform 0.3s ease-in-out; width: 100%; max-width: 450px; animation: fadeIn 1s ease-in-out; }

.weather-card:hover { transform: scale(1.05); }

input[type="text"] { padding: 15px; margin: 10px 0; width: 100%; max-width: 300px; border: 1px solid #ccc; border-radius: 5px; font-size: 16px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); transition: border-color 0.3s ease-in-out; }

input[type="text"]:focus { outline: none; border-color: #2196F3; }

input[type="text"]::placeholder { color: #aaa; }

button { padding: 12px 20px; margin-top: 10px; background-color: #2196F3; color: #fff; border: none; border-radius: 5px; font-size: 16px; cursor: pointer; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease-in-out, transform 0.3s ease-in-out; }

button:hover { background-color: #1565C0; transform: translateY(-3px); }

#weather-info { display: none; margin-top: 20px; animation: fadeIn 1s ease-in-out; }

#weather-icon { width: 100px; height: 100px; }

#temperature { font-size: 26px; font-weight: bold; color: #333; margin: 8px 0; }

#description { font-size: 20px; color: #555; margin-bottom: 10px; }

#wind-speed, #humidity, #date { font-size: 16px; color: #555; }

#date { margin-bottom: 5px; color: #888; }

.loading { font-size: 18px; color: #2196F3; margin-top: 20px; }

.error-message { font-size: 18px; color: #f44336; margin-top: 20px; }

@keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); }

to {
    opacity: 1;
    transform: translateY(0);
}

}

@media (max-width: 600px) { .weather-card { padding: 20px; width: 90%; }

input[type="text"] {
    font-size: 14px;
}

button {
    font-size: 14px;
}

#temperature {
    font-size: 22px;
}

#description {
    font-size: 18px;
}

#wind-speed,
#humidity,
#date {
    font-size: 14px;
}

}

JavaScript

// weather-app.component.spec.ts

import { ComponentFixture, TestBed } from '@angular/core/testing';

import { WeatherAppComponent } from './weather-app.component';

describe('WeatherAppComponent', () => { let component: WeatherAppComponent; let fixture: ComponentFixture;

beforeEach(() => {
    TestBed.configureTestingModule({
        declarations: [WeatherAppComponent]
    });
    fixture = TestBed.createComponent(WeatherAppComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
});

it('should create', () => {
    expect(component).toBeTruthy();
});

});

` JavaScript ``

// weather-app.component.ts

import { Component, OnInit } from '@angular/core'; import moment from 'moment'; import { HttpClient } from '@angular/common/http';

@Component({ selector: 'app-weather-app', templateUrl: './weather-app.component.html', styleUrls: ['./weather-app.component.css'] }) export class WeatherAppComponent implements OnInit { cityName: string = 'Pune'; weatherData: any; iconUrl: string = ''; currentDate: string = ''; loading: boolean = false; error: string = '';

private url = 'https://api.openweathermap.org/data/2.5/weather';
private apiKey = 'f00c38e0279b7bc85480c3fe775d518c';

constructor(private http: HttpClient) { }

ngOnInit(): void {
    this.getWeather();
}

getWeather(): void {
    this.loading = true;
    this.error = '';
    const fullUrl = `${this.url}?q=${this.cityName}&appid=${this.apiKey}&units=metric`;
    this.http.get(fullUrl).subscribe(
        (data: any) => {
            this.weatherData = data;
            this.iconUrl = `https://openweathermap.org/img/w/${data.weather[0].icon}.png`;
            this.currentDate = moment().format('MMMM Do YYYY, h:mm:ss a');
            document.getElementById('weather-info')?.style.setProperty('display', 'block');
            this.loading = false;
        },
        (error) => {
            this.error = 'City not found. Please try again.';
            this.loading = false;
            console.error('Error fetching weather data:', error);
        }
    );
}

}

``

**App Component

Below mentioned is the App Component having app.component.html, app.module.ts and app.component.ts file. Having selector of weather component in HTML file and necessary imports in app.module.ts file.

HTML `

JavaScript

// app.component.ts

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

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

JavaScript

// app.module.ts

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { WeatherAppComponent } from './weather-app/weather-app.component'; import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { FormsModule } from '@angular/forms';

@NgModule({ declarations: [ AppComponent, WeatherAppComponent ], bootstrap: [AppComponent], imports: [BrowserModule, FormsModule], providers: [provideHttpClient(withInterceptorsFromDi())] }) export class AppModule { }

`

**Complete Code:

HTML `

GeeksforGeeks

Weather App Using Angular

Get Weather
    <div *ngIf="loading" class="loading">
        Loading...
    </div>

    <div *ngIf="error" class="error-message">
        {{ error }}
    </div>

    <div *ngIf="weatherData" class="animate__animated animate__fadeIn" id="weather-info">
        <h3 id="city-name">{{ weatherData.name }}</h3>
        <p id="date">{{ currentDate }}</p>
        <img [src]="iconUrl" alt="Weather Icon" id="weather-icon">
        <p id="temperature">{{ weatherData.main.temp }}°C</p>
        <p id="description">{{ weatherData.weather[0].description }}</p>
        <p id="humidity">Humidity: {{ weatherData.main.humidity }}%</p>
        <p id="wind-speed">Wind Speed: {{ weatherData.wind.speed }} m/s</p>
    </div>
</div>

HTML

CSS

/weather-app.component.css/

body { margin: 0; font-family: 'Montserrat', sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; background: linear-gradient(to right, #4CAF50, #2196F3); }

.container { text-align: center; display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 20px; }

.weather-card { background-color: rgba(255, 255, 255, 0.95); border-radius: 20px; border: 2px solid #f44336; padding: 30px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); transition: transform 0.3s ease-in-out; width: 100%; max-width: 450px; animation: fadeIn 1s ease-in-out; }

.weather-card:hover { transform: scale(1.05); }

input[type="text"] { padding: 15px; margin: 10px 0; width: 100%; max-width: 300px; border: 1px solid #ccc; border-radius: 5px; font-size: 16px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); transition: border-color 0.3s ease-in-out; }

input[type="text"]:focus { outline: none; border-color: #2196F3; }

input[type="text"]::placeholder { color: #aaa; }

button { padding: 12px 20px; margin-top: 10px; background-color: #2196F3; color: #fff; border: none; border-radius: 5px; font-size: 16px; cursor: pointer; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease-in-out, transform 0.3s ease-in-out; }

button:hover { background-color: #1565C0; transform: translateY(-3px); }

#weather-info { display: none; margin-top: 20px; animation: fadeIn 1s ease-in-out; }

#weather-icon { width: 100px; height: 100px; }

#temperature { font-size: 26px; font-weight: bold; color: #333; margin: 8px 0; }

#description { font-size: 20px; color: #555; margin-bottom: 10px; }

#wind-speed, #humidity, #date { font-size: 16px; color: #555; }

#date { margin-bottom: 5px; color: #888; }

.loading { font-size: 18px; color: #2196F3; margin-top: 20px; }

.error-message { font-size: 18px; color: #f44336; margin-top: 20px; }

@keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); }

to {
    opacity: 1;
    transform: translateY(0);
}

}

@media (max-width: 600px) { .weather-card { padding: 20px; width: 90%; }

input[type="text"] {
    font-size: 14px;
}

button {
    font-size: 14px;
}

#temperature {
    font-size: 22px;
}

#description {
    font-size: 18px;
}

#wind-speed,
#humidity,
#date {
    font-size: 14px;
}

}

JavaScript

// weather-app.component.spec.ts

import { ComponentFixture, TestBed } from '@angular/core/testing';

import { WeatherAppComponent } from './weather-app.component';

describe('WeatherAppComponent', () => { let component: WeatherAppComponent; let fixture: ComponentFixture;

beforeEach(() => {
    TestBed.configureTestingModule({
        declarations: [WeatherAppComponent]
    });
    fixture = TestBed.createComponent(WeatherAppComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
});

it('should create', () => {
    expect(component).toBeTruthy();
});

});

` JavaScript ``

// weather-app.component.ts

import { Component, OnInit } from '@angular/core'; import moment from 'moment'; import { HttpClient } from '@angular/common/http';

@Component({ selector: 'app-weather-app', templateUrl: './weather-app.component.html', styleUrls: ['./weather-app.component.css'] }) export class WeatherAppComponent implements OnInit { cityName: string = 'Pune'; weatherData: any; iconUrl: string = ''; currentDate: string = ''; loading: boolean = false; error: string = '';

private url = 'https://api.openweathermap.org/data/2.5/weather';
private apiKey = 'f00c38e0279b7bc85480c3fe775d518c';

constructor(private http: HttpClient) { }

ngOnInit(): void {
    this.getWeather();
}

getWeather(): void {
    this.loading = true;
    this.error = '';
    const fullUrl = `${this.url}?q=${this.cityName}&appid=${this.apiKey}&units=metric`;
    this.http.get(fullUrl).subscribe(
        (data: any) => {
            this.weatherData = data;
            this.iconUrl = `https://openweathermap.org/img/w/${data.weather[0].icon}.png`;
            this.currentDate = moment().format('MMMM Do YYYY, h:mm:ss a');
            document.getElementById('weather-info')?.style.setProperty('display', 'block');
            this.loading = false;
        },
        (error) => {
            this.error = 'City not found. Please try again.';
            this.loading = false;
            console.error('Error fetching weather data:', error);
        }
    );
}

}

`` JavaScript `

// app.component.ts

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

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

JavaScript

// app.module.ts

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { WeatherAppComponent } from './weather-app/weather-app.component'; import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { FormsModule } from '@angular/forms';

@NgModule({ declarations: [ AppComponent, WeatherAppComponent ], bootstrap: [AppComponent], imports: [BrowserModule, FormsModule], providers: [provideHttpClient(withInterceptorsFromDi())] }) export class AppModule { }

`

Open the terminal, run this command from your root directory to start the application

ng serve --open

Open your browser and navigate to **http://localhost:4200

**Output