I have a countryList array with the following structure:
export const countryList = [
{name: 'Singapore', code: 'SG', cities:[
"Ang Mo Kio New Town",
"Ayer Raja New Town",
"Bedok New Town",
"Boon Lay",
"Bukit Batok New Town",
"Bukit Panjang New Town",
"Bukit Timah",
"Bukit Timah Estate",
"Changi Village",
"Choa Chu Kang New Town",
"Clementi New Town",
"Holland Village",
"Hougang",
"Jurong East New Town",
"Jurong Town",
"Jurong West New Town",
"Kalang",
"Kampong Pasir Ris",
"Kembangan",
"Pandan Valley",
"Pasir Panjang",
"Punggol",
"Queenstown Estate",
"Serangoon",
"Simei New Town",
"Singapore",
"Tai Seng",
"Tampines New Town",
"Tanglin Halt",
"Tanjong Pagar",
"Toa Payoh New Town",
"Woodlands New Town",
"Yew Tee",
"Yishun New Town"
]},
{name: 'Bahrain', code: 'BH',cities:[
"Al Budayyi`",
"Al Hadd",
"Al Hamalah",
"Al Janabiyah",
"Al Markh",
"Al Muharraq",
"Bani Jamrah",
"Barbar",
"Jurdab",
"Madinat `Isa",
"Madinat Hamad",
"Manama",
"Oil City",
"Sanabis",
"Sanad",
"Sitrah",
"Tubli"
],},
];
I have a dropdown list of all the countries in the world, and now I want when a user selects a specific country, for instance Singapore it would populate only the available cities for Singapore
Here is what i tried so far:
const [fromCountires, setFromCountries] = useState("");
const [fromCity, setFromCity] = useState();
const handleFromCountries = e => {
const country = countryList.find(
country => country.name === e.target.value
);
const cities = country.cities?.find(city => city.cities === country);
setFromCountries(country.name);
setFromCity(cities.cities);
setFromCountriesCode(country.code);
};
useEffect(() => {
console.log(fromCountires);
console.log(fromCountriesCode);
}, [fromCountires, fromCountriesCode]);
return (
<>
//this is the drop down that shows all the countries
<Form.Select
aria-label="Select Country"
onChange={e => handleFromCountries(e)}
>
<option></option>
{countryList.map((country, key) => (
<option key={key} title={country.code} value={country.name}>
{country.name}
</option>
))}
</Form.Select>
//this is the drop down that i want the cities to populate inside
for the selected country only. but it isn't working as expected and
is throwing errors.
<Form.Label className={"fw-bold"}>City</Form.Label>
<Form.Select
aria-label="Select City"
onChange={e => handleFromCountries(e)}
>
<option></option>
{fromCity.map((city, key) => (
<option key={key} title="" value={city.cities}>
{city.cities}
</option>
))}
</Form.Select>
</>
);
How can I achieve this with the data structure that I have?
CodePudding user response:
The way you have tried to set the selected city has some issues.
fromCity(formCities) state should be initialized to empty array.setFromCity(cities.cities)should besetFromCity(country.cities){city.cities}should be{city}
Try like below.
function App() {
const [fromCountires, setFromCountries] = useState("");
const [fromCities, setFromCities] = useState([]);
const handleFromCountries = (e) => {
const country = countryList.find(
(country) => country.name === e.target.value
);
setFromCountries(country.name);
setFromCities(country.cities);
};
return (
<Form.Group controlId="custom-select">
<Form.Label>Select Country</Form.Label>
<Form.Control
as="select"
className="rounded-0 shadow"
onChange={(e) => handleFromCountries(e)}
>
<option className="d-none" value="">
Select Country
</option>
{countryList.map((country, key) => (
<option key={key} title={country.code} value={country.name}>
{country.name}
</option>
))}
</Form.Control>
<Form.Label>Select City</Form.Label>
<Form.Control as="select" className="rounded-0 shadow">
<option className="d-none" value="">
Select City
</option>
{fromCities.map((city, key) => (
<option key={key} title="" value={city}>
{city}
</option>
))}
</Form.Control>
</Form.Group>
);
}
export default App;
