mateuszj
mateuszj

Reputation: 91

Cannot read properties of undefined error in dependent dropdown list

Im trying to make dependent dropdown list. In the first one menu i choose car brand. In 2nd menu I should see only models of selected brand. In a function selectBrand I am trying to set new value of selectedBrand and set models of selected brand to models arrays but in 2nd setAdData I get Uncaught TypeError: Cannot read properties of undefined (reading 'models'). How Can I fix that?

const [adData, setAdData] = useState({
    selectedBrand: "",
    models: [],
    selectedModel: "",
    productionYear: "",
    countryOfOrigin: "",
    typeOfFuel: "",
    bodyType: "",
    amountOfDoors: "",
    typeOfGearbox: "",
    typeOfDrive: "",
    color: "",
    typeOfColor: "",
    description: "",
    vin: "",
    engineCapacity: "",
    mileage: "",
    horsePower: "",
    price: "",
    creator: "",
    image: "",
});

const selectBrand = (e) => {
    setAdData({...adData, selectedBrand: e.target.value});
    setAdData({...adData, models: data.cars.find(car => car.brand===e.target.value).models})
}

return (
    <Paper className={classes.paper}>
        <form autoComplete="off" noValidate className={`${classes.root} ${classes.form}`} onSubmit={handleSubmit}>
            
        <Typography variant="h6">Brand</Typography>
        <Select fullWidth value={adData.selectedBrand} onChange={selectBrand.bind(this)
        }>
            {data.cars.map((car, key) => {
                return <MenuItem key={key} value= {car}>{car.brand}</MenuItem>
            })}
        </Select>

        <Typography variant="h6">Model</Typography>
        <Select fullWidth value={adData.selectedModel} onChange={(e) => 
            setAdData({...adData, selectedModel: e.target.value})
        }>
            {
                adData.models.map((model, key) => {
                    return <MenuItem key={key} value={model}>{model}</MenuItem>
                })
            }
        </Select>

        <Button className={classes.buttonSubmit} variant="contained" color="primary" size="large" type="submit" fullWidth>Dodaj</Button>
        <Button variant="contained" color="secondary" size="large" onClick={clear} fullWidth>Anuluj</Button>
        </form>
    </Paper>
);

data.json where I have cars and models

{
"cars":[
   {
      "brand":"BMW",
      "models":[
         "Seria 1",
         "Seria 2",
         "Seria 3",
         "Seria 4",
         "Seria 5",
         "Seria 6",
         "Seria 7",
         "Seria 8"
      ]
   },
   {
      "brand":"Audi",
      "models":[
         "A1",
         "A2",
         "A3",
         "A4",
         "A5",
         "A6",
         "A7",
         "A8"
      ]
   }
],                                                                              
}

Upvotes: 0

Views: 952

Answers (1)

Tushar Gupta
Tushar Gupta

Reputation: 15923

That's because in case the user selected car brand does not exist in data.cars, and .find() returns undefined, then you try to read .models of undefined which gives you an error

One option is you can have a ternary operator to check if find returns an array, then get the models like below (replace BMW with e.target.value )

data.cars.find(car => car.brand === "BMW") ? data.cars.find(car => car.brand === "BMW").models : []

Concept Working eg

var data = {
  "cars": [{
      "brand": "BMW",
      "models": [
        "Seria 1",
        "Seria 2",
        "Seria 3",
        "Seria 4",
        "Seria 5",
        "Seria 6",
        "Seria 7",
        "Seria 8"
      ]
    },
    {
      "brand": "Audi",
      "models": [
        "A1",
        "A2",
        "A3",
        "A4",
        "A5",
        "A6",
        "A7",
        "A8"
      ]
    }
  ]
}

console.log(data.cars.find(car => car.brand === "sd") ? data.cars.find(car => car.brand === "sd").models : []);

console.log(data.cars.find(car => car.brand === "BMW") ? data.cars.find(car => car.brand === "BMW").models : []);
  

Upvotes: 1

Related Questions