Reputation: 69
I am trying to implement cascading dropdowns in angular using angular material.
But I am unable to take corresponding values.
Could anyone please help me with this?
<mat-form-field>
<mat-select [formControl]="country" placeholder="select"
#singleSelect>
<mat-option *ngFor="let country of countries.Countries"
[value]="domain">
{{country.CountryName}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-select [formControl]="state"
placeholder="select" #singleSelect>
<mat-option *ngFor="let i=0;let state of countries.Countries"
[value]="domain">
{{state.CountryName[i].states.stateName}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-select [formControl]="city"
placeholder="select" #singleSelect>
<mat-option *ngFor="let i=0;let j=0;let city of countries.Countries"
[value]="domain">
{{city.CountryName[i].states[j].CityName}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-select [formControl]="municipality"
placeholder="select" #singleSelect>
<mat-option
*ngFor="let i=0;let j=0;k=0;let
municipality of countries.Countries"
[value]="domain">
{{municipality.city.CountryName[i].states[j].Cities[k].MunName}}
</mat-option>
</mat-select>
</mat-form-field>
[
{
"Countries":[
{
"id":0,
"CountryName":"Indonesia",
"States":[
{
"id":0,
"StateName":"Bali",
"Cities":[
{
"id":0,
"CityName":"Denpasar",
"Municipalities":[
{
"id":0,
"MunName":"Mun1"
},
{
"id":1,
"MunName":"Mun2"
},
{
"id":2,
"MunName":"Mun3"
}
]
},
{
"id":1,
"CityName":"Kuta",
"Municipalities":[
{
"id":0,
"MunName":"Mun4"
},
{
"id":1,
"MunName":"Mun5"
},
{
"id":2,
"MunName":"Mun6"
}
]
},
{
"id":2,
"CityName":"Tuban",
"Municipalities":[
{
"id":0,
"MunName":"Mun7"
},
{
"id":1,
"MunName":"Mun8"
},
{
"id":2,
"MunName":"Mun9"
}
]
}
]
},
{
"id":1,
"StateName":"Badgis",
"Cities":[
{
"id":0,
"CityName":"Denpasar",
"Municipalities":[
{
"id":0,
"MunName":"Mun1"
},
{
"id":1,
"MunName":"Mun2"
},
{
"id":2,
"MunName":"Mun3"
}
]
},
{
"id":1,
"CityName":"Andarab",
"Municipalities":[
{
"id":0,
"MunName":"Mun4"
},
{
"id":1,
"MunName":"Mun5"
},
{
"id":2,
"MunName":"Mun6"
}
]
}
]
}
]
},
{
"id":1,
"CountryName":"India",
"States":[
{
"id":0,
"StateName":"Delhi",
"Cities":[
{
"id":0,
"CityName":"Sonipat",
"Municipalities":[
{
"id":0,
"MunName":"Mun1"
},
{
"id":1,
"MunName":"Mun2"
},
{
"id":2,
"MunName":"Mun3"
}
]
},
{
"id":1,
"CityName":"Rohtak",
"Municipalities":[
{
"id":0,
"MunName":"Mun4"
},
{
"id":1,
"MunName":"Mun5"
},
{
"id":2,
"MunName":"Mun6"
}
]
}
]
},
{
"id":1,
"StateName":"Karnataka",
"Cities":[
{
"id":0,
"CityName":"Mangalore",
"Municipalities":[
{
"id":0,
"MunName":"Mun1"
},
{
"id":1,
"MunName":"Mun2"
},
{
"id":2,
"MunName":"Mun3"
}
]
},
{
"id":1,
"CityName":"Hubli",
"Municipalities":[
{
"id":0,
"MunName":"Mun4"
},
{
"id":1,
"MunName":"Mun5"
},
{
"id":2,
"MunName":"Mun6"
}
]
}
]
}
]
}
]
}
]
Upvotes: 0
Views: 1132
Reputation: 6193
I would implement a solution where most of the logic is in the component and not in the template, as it is very difficult to understand with all the different loop variables.
The approach I am showing you in this stackblitz here, is one that subscribes to the valueChanges
property of a FormControl
and then based on the value selected, filters the values for the next FormControl
, e.g. mat-select
.
The dropdowns are displayed based on the values they are displaying. Meaning they won't be shown if the filtered values are not available and thus one dropdown after the other is shown.
This might not be the best or cleanest way to implement this, but it definitely gets the job done.
Note: I removed the surrounding
[]
from yourcountries
object. They are not needed.
Key points from the template: Use *ngIf
to conditionally display the state, city and municipality inputs (based on the pre-filtered values, see component code).
<mat-form-field>
<mat-select [formControl]="country" placeholder="Select Country" #countrySelect>
<mat-option *ngFor="let country of countries.Countries" [value]="country.CountryName">
{{country.CountryName}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="statesFiltered && statesFiltered.length">
<mat-select [formControl]="state" placeholder="Select State" #stateSelect>
<mat-option *ngFor="let state of statesFiltered" [value]="state.StateName">
{{state.StateName}}
</mat-option>
</mat-select>
</mat-form-field>
Key points from the component: Use valueChanges
to listen for changes and filter the values for the next select element to be shown. A bit ugly: Reset the filtered values on each value change to hide the input elements further down the chain.
this.country.valueChanges.subscribe(() => {
this.statesFiltered = [];
this.citiesFiltered = [];
this.municipalitiesFiltered = [];
this.changeDetectorRef.detectChanges();
this.statesFiltered = this.countries.Countries.find(country => {
return country.CountryName === this.country.value;
}).States;
});
Upvotes: 1