In my angular app I have a scenario where I have list of countries and if I select a country it will make an API call and fetched the respective states list. Then if I select state it should display in mat-select. I have implemented the functionality but state selection is not happening.
<mat-form-field appearance="fill" class="full-width">
<mat-select placeholder="Select Country/State" [(value)]="selectedValue" #countryStateSelect (openedChange)="onDropdownOpen($event)">
<div class="dropdown-container">
<div class="dropdown-column">
<mat-option *ngFor="let country of countries" (click)="onCountrySelect(country, countryStateSelect)">
{{ country.country }}
</mat-option>
</div>
<div class="dropdown-column" *ngIf="selectedCountry">
<mat-option *ngFor="let state of selectedCountry.states" [value]="state.state" (click)="onStateSelect(state.state, countryStateSelect)">
{{ state.state }}
</mat-option>
</div>
</div>
</mat-select>
</mat-form-field>
import { Component } from '@angular/core';
import { VERSION } from '@angular/material';
import { NavItem } from './nav-item';
@Component({
selector: 'material-app',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss'],
})
export class AppComponent {
selectedCountry: any = null;
selectedValue: string = '';
countries = [
{
"country": "India",
"states": [
{ "state": "AP" },
{ "state": "TG" },
{ "state": "UP" },
{ "state": "GA" }
]
},
{
"country": "USA",
"states": [
{ "state": "TA" },
{ "state": "MG" },
{ "state": "NC" },
{ "state": "NY" }
]
},
{
"country": "Canada",
"states": [
{ "state": "ON" },
{ "state": "BC" }
]
}
];
onCountrySelect(country: any, select: MatSelect) {
this.selectedCountry = country;
select.open();
}
onStateSelect(state: string, select: MatSelect) {
this.selectedValue = state;
this.selectedCountry = null;
select.close();
}
onDropdownOpen(isOpen: boolean) {
if (!isOpen) {
this.selectedCountry = null;
}
}
}
here is the example Stackblitz Demo
Can someone help me.
When you clear the selectedCountry
the options are not available inside the select, so you are getting the selection. Instead do not set, selectedCountry to null. Also instead of value
two way binding, go for ngModel
instead.
import { Component } from '@angular/core';
import { VERSION } from '@angular/material';
import { NavItem } from './nav-item';
import { MatSelect } from '@angular/material/select';
@Component({
selector: 'material-app',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss'],
})
export class AppComponent {
selectedCountry: any = null;
selectedValue: string = '';
countries = [
{
country: 'India',
states: [
{ state: 'AP' },
{ state: 'TG' },
{ state: 'UP' },
{ state: 'GA' },
],
},
{
country: 'USA',
states: [
{ state: 'TA' },
{ state: 'MG' },
{ state: 'NC' },
{ state: 'NY' },
],
},
{
country: 'Canada',
states: [{ state: 'ON' }, { state: 'BC' }],
},
];
ngOnInit() {
this.setSelectedValue('AP');
}
onCountrySelect(country: any, select: MatSelect) {
this.selectedCountry = country;
select.open();
}
setSelectedValue(state: any) {
const foundCountry = this.countries.find((item: any) => {
return item.states.some((data: any) => data.state === state);
});
this.selectedCountry = foundCountry;
this.selectedValue = state;
}
onStateSelect(state: string, select: MatSelect) {
this.selectedValue = state;
// this.selectedCountry = null;
select.close();
}
compareWithFn(o1: any, o2: any) {
console.log(o1, o2);
return o1 === o2;
}
onDropdownOpen(isOpen: boolean) {
if (!isOpen) {
this.selectedCountry = null;
}
}
}
<mat-form-field appearance="fill" class="full-width">
<mat-select
placeholder="Select Country/State"
[(ngModel)]="selectedValue"
#countryStateSelect
(openedChange)="onDropdownOpen($event)"
>
<div class="dropdown-container">
<div class="dropdown-column">
<mat-option
*ngFor="let country of countries"
(click)="onCountrySelect(country, countryStateSelect)"
>
{{ country.country }}
</mat-option>
</div>
<div class="dropdown-column" *ngIf="selectedCountry">
<mat-option
*ngFor="let state of selectedCountry.states"
[value]="state.state"
(click)="onStateSelect(state.state, countryStateSelect)"
>
{{ state.state }}
</mat-option>
</div>
</div>
</mat-select>
</mat-form-field>