I'm new to Typescript react, I'm trying to create two dependent select boxes fetching data from the API but having a slight difficulty. When I select colours in Category I want just colours in the Product drop down but I'm getting all other products as well and also it's appearing all colours horizontally in one option. This is what I have tried so far.
My MongoDB structure
"_id": {
"$oid": "679a70442a02723a1ad65e5d"
},
"categoryName": "Colours",
"productName": [
{
"productName": "Red"
},
{
"productName": "Blue"
},
{
"productName": "Yellow"
},
{
"productName": "Green"
}
],
"productQuantity": 90,
"ordUpdated": {
"$date": "2025-01-29T18:15:32.969Z"
},
"isInStock": false,
"_class": "com.softoffice.portal.model.OrderDTO"
Typescript
export const DependentDropdown = () => {
const [selectedCateogary, setSelectedCategory] = useState('');
const [selectedProd, setSelectedProd] = useState([]);
const { data } = useQuery({
queryKey: ["ordlist"],
queryFn: () => fetch("http://localhost:8080/portal")
.then((res) => res.json())
})
const products = data?.map((row: any) => ({
productName: row.productName?.map((p: { productName: string; }) => p.productName)
}))
const handleChange = (id:string) => {
const pd = products.filter((c: any) => c.categoryName === id);
setSelectedProd(pd);
}
return (
<div>
<InputLabel id="demo-simple-select-label">Category</InputLabel>
<select className='select' onChange={(e) => handleChange(e.target.value)} >
<option>Select Category</option>
{data?.map((row: { categoryName: any }) => (
<option>{row.categoryName}</option>
))}
</select>
<InputLabel id="demo-simple-select-label">Product</InputLabel>
<select className='select' >
<option>Select Product</option>
{data?.map((row: { productName: any }) => (
<option>{row.productName?.map((p: { productName: string; }) => p.productName)}</option>
))}
</select>
</div>
);
}
you can try a different approach for the handleChangeCategory like this:
const handleCategoryChange = (categoryName: string) => {
setSelectedCategory(categoryName);
// Find the selected category in data and get its product names
const selectedCategoryData = data?.find(
(item: any) => item.categoryName === categoryName
);
if (selectedCategoryData) {
// Extract product names as an array of strings
const productNames = selectedCategoryData.productName.map(
(p: { productName: string }) => p.productName
);
setSelectedProducts(productNames);
} else {
setSelectedProducts([]); // Reset if no matching category
}
};
and then refactor a little bit the Select products component code like this:
<label>Product</label>
<select className="select">
<option>Select Product</option>
{selectedProducts.map((product, index) => (
<option key={index} value={product}>
{product}
</option>
))}
</select>