Search code examples
mongodbreact-typescript

Dependent dropdown boxes in typescript react not working


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.

enter image description here

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>
  );
}

Solution

  • 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>