Home > Net >  How to capture onChange event from a field with object type State
How to capture onChange event from a field with object type State

Time:04-28

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: Edit React-Update-Nested-State-Array

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
            }
          ]
        }
      };
    });
  • Related