I am unable to capture the onChange event from a Obect which contains multiple object fields in itself.
Here is my useState hook.
const [train, setTrain] = useState({
trainNumber: "",
trainName: "",
fromStation: "",
toStation: "",
departureDateTime: "",
arrivalDateTime: "",
//unable to capture travelDetails property changes.
travelDetails: {
coachesClass: [
{
availableTickets: "",
travelClass: "",
fare: "",
},
],
},
});
Suppose I want to check the onChange event for travelDetails.coachesClass[0].availableTickets then how to do that?
<div className="row">
<label htmlFor="availableTickets">First AC</label>
<div className="col-4">
<input
type="number"
name="availableTickets"
className="form-control"
placeholder="Available Tickets"
required
value={train.travelDetails.coachesClass[0].availableTickets}
onChange={(e) => handleChange(e)}
/>
</div>
Here is the onChangeHandler
const handleChange = (e) => {
const { name, value } = e.target;
setTrain((prevState) => {
return {
...prevState,
[name]: value,
};
});
};
It is working fine for other fields but inside travelDetails it is not capturing changes.
CodePudding user response:
The way you are updating state will need to be adjusted since you are trying to update a property in an array nested within an object. Try something like this:
const handleChange = (e) => {
setTrain((prevState) => {
const newCoachesClass = [...prevState.travelDetails.coachesClass];
newCoachesClass[0] = {
...prevState.travelDetails.coachesClass[0],
availableTickets: e.target.value
};
return {
...prevState,
travelDetails: {
...prevState.travelDetails,
coachesClass: newCoachesClass
}
};
});
};
Also since your input
is of number
type, you probably want to initialize availableTickets
to a number instead of a string:
const [train, setTrain] = useState({
trainNumber: "",
trainName: "",
fromStation: "",
toStation: "",
departureDateTime: "",
arrivalDateTime: "",
travelDetails: {
coachesClass: [
{
availableTickets: 0,
...
Check out this codepen for an example:
CodePudding user response:
Currently, your setState adds a new property on the state's object itself. Since it looks like you want that information to update your nested state, see updated snippet below:
const handleChange = (e) => {
const { name, value } = e.target;
setTrain((prevState) => {
return {
...prevState,
travelDetails: {
...prevState.travelDetails,
coachesClass: [
{
...prevState.travelDetails.coachesClass[0],
[name]: value
}
]
}
};
});