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.