API Based Weather Application with Angular

This step-by-step guide will teach you how to create a API Based Weather Application using Angular, Shows Live Temperature of the City

Step 1 – Create Angular App

Run the following command to create a new Angular project:

ng new weather-app  --no-standalone --routing --ssr=false

Run the following command to install jquery, popperjs, and bootstrap :

cd weather-app

npm install jquery --save
npm install @popperjs/core --save
npm install ngx-bootstrap bootstrap@latest
ng add ngx-bootstrap

Run the following command to install Angular Ant Design:

ng add ng-zorro-antd

Your Application Folder Structure will be like:

src
├── app
│   ├── home
│   │   ├── home.component.html
│   │   ├── home.component.css
│   │   └── home.component.ts
│   ├── service
│   │   └── weather-api.service.ts
│   ├── app.component.html
│   ├── app.component.ts
│   ├── app.module.ts
│   ├── app-routing.module.ts	
├── index.html
├── style.css

Step 2 – Project Setup

Copy and Paste following code styles section of angular.json file:

"./node_modules/bootstrap/dist/css/bootstrap.min.css"
						

Copy and Paste following code script section of angular.json file:

"./node_modules/jquery/dist/jquery.min.js",
"./node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"

						

Step 3 – Create Home Component for Dashboard

Create Home Component for Dashboard with the following command:

ng generate component --skip-tests=true home

You will get:

home.component.html
home.component.css
home.component.ts
						

Copy and Paste the following code to home.component.html:

<div class="container mt-5">
  <h2 class="text-center mb-4">Search Weather</h2>
  <div class="search-container">
    <form (submit)="searchCity()" class="search-form">
      <input
        type="text"
        [(ngModel)]="cityName"
        name="city"
        class="search-input"
        placeholder="Enter city name"
      />
      <button type="submit" class="search-btn">
        <span nz-icon nzType="search"></span>
      </button>
    </form>
  </div>

  <div class="container text-center mt-5" *ngIf="weatherData">
    <h2>Weather in {{ weatherData.location.name }}</h2>
    <div class="card">
      <div class="card-body">
        <h4 class="card-title">{{ weatherData.location.name }}, {{ weatherData.location.country }}</h4>
        <strong>Temperature:</strong> {{ weatherData.current.temp_c }}°C<br />
        <strong>Condition:</strong> {{ weatherData.current.condition.text }}<br />
        <strong>Humidity:</strong> {{ weatherData.current.humidity }}%<br />
        <strong>Wind Speed:</strong> {{ weatherData.current.wind_kph }} km/h
        <img
          [src]="weatherData.current.condition.icon"
          alt="weather icon"
          class="img-fluid"
        />
      </div>
    </div>
  </div>
</div>
 

Copy and Paste the following code to home.component.ts :

import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {WeatherApiService} from "../service/weather-api.service";

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css'],
})
export class HomeComponent implements OnInit {
  cityName = '';
  weatherData: any;

  constructor(private router: Router,
              private route: ActivatedRoute,
              private weatherApi: WeatherApiService) {}


  searchCity() {
    if (this.cityName) {
      this.router.navigate(['/'], {
        queryParams: { city: this.cityName },
      });
    }
  }

  ngOnInit() {
    this.route.queryParams.subscribe((params) => {
      this.cityName = params['city'];
      this.getWeatherData(this.cityName);
    });
  }
  getWeatherData(city: string) {
    this.weatherApi.getWeather(city).subscribe((data) => {
      this.weatherData = data;
    });
  }
}
 

Copy and Paste the following code to app.component.html for Navigation Menu:

 <nav class="navbar navbar-expand-lg sticky-top bg-white">
  <div class="container justify-content-center align-items-center">
    <a class="navbar-brand" href="#">Weather App</a>
  </div>
</nav> 

Copy and Paste the following code to app-routing.module.ts at import section:

 import { HomeComponent} from "./home/home.component"; 

Copy and Paste the following code to app-routing.module.ts at const routes: Routes section:

 { path: '', component: HomeComponent }, 

Add following code to app.component.html for Routing to Dashboard:

 <router-outlet></router-outlet> 

Step 4 – Create Service for Weather API

Run following Command to create weather-api service:

 ng generate service service/weather-api --skip-tests 

You will get weather-api.service.ts file in model directory:

Copy and Paste the following code to weather-api.service.ts:

 import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class WeatherApiService {
  private apiKey = 'Your_API_Key';
  private baseUrl = 'https://api.weatherapi.com/v1/current.json';

  constructor(private http: HttpClient) {}

  getWeather(city: string): Observable {
    const url = `${this.baseUrl}?key=${this.apiKey}&q=${city}`;
    return this.http.get(url);
  }
}

Follow these 3 steps to get your API key:

Sign Up and Get API Key
1. Go to https://www.weatherapi.com/.
2. Sign up for a free account.
3. Get your API key from the dashboard.

Step 5 – Add CSS

Copy and Paste the following CSS code to style.css:

 /* Responsive container */
.container {
  max-width: 600px;
  padding: 15px;
  margin: auto;
}

/* Weather card responsiveness */
.card {
  margin: 20px auto;
  max-width: 400px;
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 10px;
  box-shadow: 25px 25px 49px #dedede,
  -25px -25px 49px #ffffff;
}

.card-body img {
  max-width: 50px;
  margin-bottom: 10px;
}

.card-text {
  font-size: 14px;
}
/* Responsive Navbar */
@media screen and (max-width: 768px) {
  .navbar a, .navbar-brand {
    display: block;
    text-align: center;
    width: 100%;
  }

  .card {
    max-width: 90%;
  }

  .card-text {
    font-size: 12px;
  }
}
/* Center and style the search container */
.search-container {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* Form styling */
.search-form {
  display: flex;
  width: 100%;
  max-width: 400px;
  position: relative;
}

/* Input styling */
.search-input {
  width: 100%;
  padding: 15px 20px;
  font-size: 16px;
  border: 2px solid #dcdcdc;
  border-radius: 50px;
  outline: none;
  transition: all 0.3s ease-in-out;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  padding-right: 60px;
}

/*Button styling*/
.search-btn {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  background-color: #fff;
  color: black;
  border: none;
  border-radius: 50%;
  padding: 10px 14px;
  font-size: 18px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Responsive Design */
@media screen and (max-width: 768px) {
  .search-input {
    font-size: 14px;
    padding: 12px 16px;
  }

  .search-btn {
    padding: 8px 12px;
    font-size: 16px;
  }
}
.navbar {
  box-shadow: 6px 6px 12px #c5c5c5, -6px -6px 12px #ffffff;
}

.navbar-brand {
  font-size: 1.5rem;
  font-weight: bold;
  /*text-indent: 209px;*/
}

.nav-link {
  font-size: 1rem;
  margin: 0 5px;
}

.nav-link.active {
  font-weight: bold;
  text-decoration: underline;
}