Angular 16 Country State City Dropdowns Tutorial

To dynamic cascading dropdowns to improve user experience and streamline location-based data entry in angular apps.

So In this tutorial, you will learn how to create dynamic cascading dropdowns for countries, states, and cities in an Angular 16 project.

Country State City Dropdowns in Angular 16 Project

Steps to implement dynamic cascading dropdowns for countries, states, and cities in angular 16 projects:

  • Step 1: Set Up Your Angular Project
  • Step 2: Install Bootstrap and Material
  • Step 3: Create Components, Modules & Service files
  • Step 4: Create Dropdown in HTML Components
  • Step 5: Implement Dropdown Logic in Component
  • Step 6: Implement Dropdown Logic in Component
  • Step 7: Implement Services to Fetch Data
  • Step 8: Run the Application

Step 1: Set Up Your Angular Project

First of all, open your cmd or command prompt and execute the following command into it to install and create angular project using the Angular CLI:

npm install -g @angular/cli
ng new angular-country-state-city-dropdowns
cd angular-country-state-city-dropdowns

Step 2: Install Bootstrap and Material

Next, you need to execute the following command on cmd to install bootstrap and material in your angular project:

npm install bootstrap
ng add @angular/material

Once you have executed above commands, now you need to open angular.json file, inside architect > build > styles array add a new item "./node_modules/bootstrap/dist/css/bootstrap.min.css"

Step 3: Create Components, Modules & Service files

Next, you need to create a component, module, and services file. So, open cmd and execute the following command into it:

ng generate module angular-material
ng generate service services/dropdown

Then open AngularMaterialModule file and add the following code to it:

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';

const materialModules = [
  MatInputModule,
  MatProgressBarModule,
  MatProgressSpinnerModule,
  MatSelectModule,
  MatFormFieldModule,
];
@NgModule({
  imports: [CommonModule, ...materialModules],
  exports: [...materialModules],
})
export class AngularMaterialModule {}

After that, you need to import this file into the AppModule file as below.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AngularMaterialModule } from './angular-material.module';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    AngularMaterialModule, // <--added
    HttpClientModule, // <--added
    FormsModule, // <--added
    ReactiveFormsModule, // <--added
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

Step 4: Create Dropdown in HTML Components

Next, you need to create dropdown html. So, open app.component.html file. And add the following code to your app.component.html file:

<mat-progress-bar
  mode="indeterminate"
  color="accent"
  *ngIf="loading"
></mat-progress-bar>

<div class="container mt-4">
  <div class="mt-3 mb-3" style="text-align: center">

  </div>
  <div class="card example-card" style="width: 50rem">
    <div class="card-body">
      <h5 class="card-title text-center m-2">Country, State & City Dropdown</h5>
      <form [formGroup]="dropdownForm">
        <div class="d-flex justify-content-center mt-4">
          <div class="p-2">
            <mat-form-field appearance="outline">
              <mat-label>Country</mat-label>
              <mat-select
                disableRipple
                formControlName="country"
                (valueChange)="selectCountry($event)"
              >
                <mat-option value="">Select</mat-option>
                <mat-option
                  *ngFor="let country of countries"
                  [value]="country.id"
                  [attr.data-country-name]="country.name"
                  >{{ country.name }}
                </mat-option>
              </mat-select>
            </mat-form-field>
          </div>
          <div class="p-2">
            <mat-form-field appearance="outline">
              <mat-label>State</mat-label>
              <mat-select
                disableRipple
                formControlName="state"
                (valueChange)="selectState($event)"
              >
                <mat-option value="">Select</mat-option>
                <mat-option
                  *ngFor="let state of states"
                  [value]="state.id"
                  [attr.data-state-name]="state.name"
                  >{{ state.name }}
                </mat-option>
              </mat-select>
            </mat-form-field>
          </div>
          <div class="p-2">
            <mat-form-field appearance="outline">
              <mat-label>City</mat-label>
              <mat-select disableRipple formControlName="city">
                <mat-option value="">Select</mat-option>
                <mat-option
                  *ngFor="let city of cities"
                  [value]="city.id"
                  [attr.data-city-name]="city.name"
                  >{{ city.name }}
                </mat-option>
              </mat-select>
            </mat-form-field>
          </div>
        </div>
        <p *ngIf="dropdownForm.value.country">
          {{ dropdownForm.value | json }}
        </p>
      </form>
    </div>
  </div>
</div>

Step 5: Implement Dropdown Logic in Component

Now, open app.component.ts file and add the following code to it:

import { Component, OnInit } from '@angular/core';
import { DropdownService } from './services/dropdown.service';
import { FormBuilder, FormGroup } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
  title = 'Country-State-City Dropdown';
  public loading = false;
  public dropdownForm!: FormGroup;
  public countries: any[] = [];
  public states: any[] = [];
  public cities: any[] = [];

  constructor(
    private dropdownService: DropdownService,
    private formBuiler: FormBuilder
  ) {}
  ngOnInit(): void {
    /**
     * Intialize form with default value null
     */
    this.dropdownForm = this.formBuiler.group({
      country: [null],
      state: [null],
      city: [null],
    });
    /**
     * load all country data at page load
     */
    this.getCountries();
  }
  /**
   * loads all country data
   * @returns void
   */
  private getCountries() {
    this.loading = true;
    this.dropdownService.getCountries().subscribe(
      (response) => {
        this.countries = response.data;
        console.log(this.countries);
        this.loading = false;
      },
      (error) => {
        console.log('Something went wrong: ', error);
      }
    );
  }

  /**
   * Selects country, and gets the states for it
   * @param country
   * @returns void
   */
  public selectCountry(country: any) {
    if (!country) {
      this.dropdownForm.controls['state'].setValue('');
      this.dropdownForm.controls['city'].setValue('');
      this.states = [];
      this.cities = [];
      return;
    }
    this.loading = true;
    const countryId = parseInt(country);
    this.dropdownService.getStates(countryId).subscribe(
      (response) => {
        this.states = response.data;
        this.loading = false;
      },
      (error) => {
        console.log('Something went wrong: ', error);
      }
    );
  }

  /**
   * Selects the state and gets cities for it
   * @param state
   * @returns void
   */
  public selectState(state: any) {
    if (!state) {
      this.dropdownForm.controls['city'].setValue('');
      this.cities = [];
      return;
    }
    this.loading = true;
    const stateId = parseInt(state);
    this.dropdownService.getCities(stateId).subscribe(
      (response) => {
        this.cities = response.data;
        this.loading = false;
      },
      (error) => {
        console.log('Something went wrong: ', error);
      }
    );
  }
}

Step 7: Implement Services to Fetch Data

Next, you need to fetch data using services in your angular dropdown. So, open dropdown.service.ts file and add the following code to it:

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

@Injectable({
  providedIn: 'root',
})
export class DropdownService {
  // Update your API path here
  private BASE_URL = environment.apiUrl;
  constructor(private http: HttpClient) {}

  /**
   * Fetch All Countries
   * @returns Observable
   */
  public getCountries(): Observable<any> {
    return this.http.get<any>(this.BASE_URL + 'getcountry');
  }
  /**
   * Get states for a country
   * @param countryId
   * @returns Observable
   */
  public getStates(countryId: number): Observable<any> {
    return this.http.get<any>(
      this.BASE_URL + 'getstate&country_id=' + countryId
    );
  }
  /**
   * Get cities for a state
   * @param stateId
   * @returns Observable
   */
  public getCities(stateId: number): Observable<any> {
    return this.http.get<any>(this.BASE_URL + 'getcity&state_id=' + stateId);
  }

Step 8: Run the Application

Now, you can run the Angular app using the following command:

ng serve

Visit http://localhost:4200/ in your browser to see the country, state, and city dropdowns in action.

Conclusion

Congratulations! You’ve successfully implemented dynamic cascading dropdowns for countries, states, and cities in an Angular 16 project.

Recommended Tutorials

AuthorDevendra Dode

Greetings, I'm Devendra Dode, a full-stack developer, entrepreneur, and the proud owner of Tutsmake.com. My passion lies in crafting informative tutorials and offering valuable tips to assist fellow developers on their coding journey. Within my content, I cover a spectrum of technologies, including PHP, Python, JavaScript, jQuery, Laravel, Livewire, CodeIgniter, Node.js, Express.js, Vue.js, Angular.js, React.js, MySQL, MongoDB, REST APIs, Windows, XAMPP, Linux, Ubuntu, Amazon AWS, Composer, SEO, WordPress, SSL, and Bootstrap. Whether you're starting out or looking for advanced examples, I provide step-by-step guides and practical demonstrations to make your learning experience seamless. Let's explore the diverse realms of coding together.

Leave a Reply

Your email address will not be published. Required fields are marked *