1

I am having a onChange function i was trying to update the array options by index wise and i had passed the index to the function.

Suppose if i am updating the options array index 0 value so only that value should be update rest should remain as it is.

Demo

Here is what i tried:

import React from "react";
import "./styles.css";

export default function App() {
  const x = {
    LEVEL: {
      Type: "LINEN",
      options: [
        {
          Order: 1,
          orderStatus: "INFO",
          orderValue: "5"
        },
        {
          Order: 2,
          orderStatus: "INPROGRESS",
          orderValue: "5"
        },
        {
          Order: 3,
          orderStatus: "ACTIVE",
          orderValue: "9"
        }
      ],
      details: "2020  N/w UA",
      OrderType: "Axes"
    },
    State: "Inprogress"
  };

  const [postdata, setPostData] = React.useState(x);

  const handleOptionInputChange = (event, idx) => {
    setPostData({
      ...postdata,
      LEVEL: {
        ...postdata.LEVEL.options,
        [event.target.name]: event.target.value
      }
    });
  };

  return (
    <div className="App">
      {postdata.LEVEL.options.map((item, idx) => {
        return (
          <input
            type="text"
            name="orderStatus"
            value={postdata.LEVEL.options[idx].orderStatus}
            onChange={e => handleOptionInputChange(e, idx)}
          />
        );
      })}
    </div>
  );
}

Suppose if i want to add the objects in another useState variable for all the updated options only, will this work?

const posting = {
        "optionUpdates": [],
    }

    const [sentdata , setSentData] = useState(posting);
    
    setSentData({
            ...sentdata,
            optionUpdates: [{
            ...sentdata.optionUpdates,
            displayOrder: event.target.value
        }]
    })

2 Answers 2

1

Basically, you need to spread properly, use callback approach to set state etc.

Change your handler to like this.

Working demo

const handleOptionInputChange = (event, idx) => {
    const target = event.target; // with callback approach of state, you can't use event inside callback, so first extract the target from event.
    setPostData(prev => ({ // prev state
      ...prev, // spread prev state
      LEVEL: { //update Level object
        ...prev.LEVEL,
        options: prev.LEVEL.options.map((item, id) => { // you need to loop thru options and find the one which you need to update.
          if (id === idx) { 
            return { ...item, [target.name]: target.value }; //spread all values and update only orderStatus
          }
          return item;
        })
      }
    }));
  };

Edit Added some comments to code and providing some explanation.

You were spreading postdata.LEVEL.options for LEVEL which is incorrect. For nested object you need to spread each level.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks , Can you please bring some comment into it so that i can easily understand.
Thanks you so much i just update a same change in question will that work? or any other solution for that
yes, it should... see the working demo link (codesandbox)
I am taking about the sentdata part which i just update inside of my question section
i see - ok ... no ur setSentData won't work...some issues are there with it ... can you show the jsx code for that as well.... perhaps please post another question regarding setSentData ... this way your reputation increases(by asking good qns) and also other experts will help u quickly...
0

Apparently, your event.target.name is "orderStatus", so it will add an "orderStatus" key to your postData.

You might want to do something like this:

const handleOptionInputChange = (value, idx) => {
  setPostData(oldValue => {
    const options = oldValue.LEVEL.options;
    options[idx].orderStatus = value;

    return {
      ...oldValue,
      LEVEL: {
        ...oldValue.LEVEL,
        options
      }
    };
  });
};

return (
  <div className="App">
    {postdata.LEVEL.options.map((item, idx) => {
      return (
        <input
          type="text"
          name="orderStatus"
          value={postdata.LEVEL.options[idx].orderStatus}
          onChange={e => handleOptionInputChange(e.target.value, idx)}
        />
      );
    })}
  </div>
);

See this demo

2 Comments

No it does not work, if i dont pass event.target.name how will it identify the name and if i pass [idx]: event.target.value then i think it will update whole object not just orderStatus
I updated the code and added a working codesandbox link

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.