Dynamic Country and State Dropdowns in Angular using Web API

Dynamic Country and State Dropdowns in Angular using Web API

When building modern web applications, especially employee forms or address inputs, it's common to let users select their country and state from a dynamic list. Instead of hardcoding these options, we’ll make them dynamic by fetching them from a backend API.

In this tutorial, we’ll walk through how to create an employee form in Angular that:

  • Loads countries from a backend API on initialization.
  • Loads states based on the selected country.
  • Submits the complete form data.

 

Backend API Structure

For this example, we'll assume an ASP.NET Web API with the following endpoints:

GET /api/countries         // Returns a list of countries

GET /api/states?countryId=1  // Returns states for a specific country

 

Each country/state might look like:

// Country

{ "id": 1, "name": "United States" }

 

// State

{ "id": 101, "name": "California", "countryId": 1 }

 

 

Step 1: Angular Setup

Ensure HttpClientModule is imported in your Angular app module:

 

import { HttpClientModule } from '@angular/common/http';

 

@NgModule({

  imports: [HttpClientModule]

})

export class AppModule {}

 

 

Step 2: Creating the Country Service

We’ll create a service to communicate with our API.

 

// country.service.ts

import { HttpClient } from '@angular/common/http';

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

import { Observable } from 'rxjs';

 

@Injectable({ providedIn: 'root' })

export class CountryService {

  private apiUrl = 'https://yourapi.com/api';

 

  constructor(private http: HttpClient) {}

 

  getCountries(): Observable<any[]> {

    return this.http.get<any[]>(`${this.apiUrl}/countries`);

  }

 

  getStatesByCountryId(countryId: number): Observable<any[]> {

    return this.http.get<any[]>(`${this.apiUrl}/states?countryId=${countryId}`);

  }

}

 

 

Step 3: Building the Employee Form Component

Here’s how we use FormBuilder to create the reactive form and bind it to dynamic data:

 

// employee-form.component.ts

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

import { FormBuilder, FormGroup } from '@angular/forms';

import { CountryService } from '../services/country.service';

 

@Component({

  selector: 'app-employee-form',

  templateUrl: './employee-form.component.html'

})

export class EmployeeFormComponent implements OnInit {

  form: FormGroup;

  countries: any[] = [];

  states: any[] = [];

 

  constructor(private fb: FormBuilder, private countryService: CountryService) {

    this.form = this.fb.group({

      name: [''],

      country: [''],

      state: ['']

    });

  }

 

  ngOnInit() {

    this.countryService.getCountries().subscribe(data => {

      this.countries = data;

    });

 

    this.form.get('country')?.valueChanges.subscribe(countryId => {

      if (countryId) {

        this.countryService.getStatesByCountryId(countryId).subscribe(states => {

          this.states = states;

          this.form.get('state')?.setValue('');

        });

      } else {

        this.states = [];

        this.form.get('state')?.setValue('');

      }

    });

  }

 

  onSubmit() {

    console.log('Form submitted:', this.form.value);

  }

}

 

 

Step 4: Template for the Employee Form

Here's the HTML form using Angular’s reactive form binding:

 

<!-- employee-form.component.html -->

<form [formGroup]="form" (ngSubmit)="onSubmit()">

  <label>Name:</label>

  <input formControlName="name" type="text" />

 

  <label>Country:</label>

  <select formControlName="country">

    <option value="">Select Country</option>

    <option *ngFor="let country of countries" [value]="country.id">

      {{ country.name }}

    </option>

  </select>

 

  <label>State:</label>

  <select formControlName="state" [disabled]="!states.length">

    <option value="">Select State</option>

    <option *ngFor="let state of states" [value]="state.id">

      {{ state.name }}

    </option>

  </select>

 

  <button type="submit">Submit</button>

</form>

 

 Result

When a user selects a country:

  • The list of states is automatically updated.
  • The form updates dynamically and remains reactive.
  • The selected values are logged or submitted as needed.

 Final Tips

  • Always handle errors from API calls using catchError() in production apps.
  • Use type interfaces (Country, State) to strongly type your API data.
  • Consider caching countries if they rarely change to reduce backend calls.

 Conclusion

You now have a fully dynamic, reactive form in Angular that populates country and state fields from a backend API. This is a common pattern in real-world applications, and mastering it helps you create flexible, scalable forms.

Comments

Popular posts from this blog

Promises in Angular

Mastering Your Angular Workflow: Essential CLI Commands for Efficient Development

Observables in Angular