1

I'm trying to add an extra input field if user clicks add input button and store those values as an object:

const {useState } = React;

const InviteUser = () => {
  const [userDetails, setUserDetails] = useState([
    {
      email: "",
      role: ""
    }
  ]);

  const handleCancel = () => {
    setUserDetails([
      {
        email: "",
        role: ""
      }
    ]);
  };

  const handleChange = (e, index) => {
    const { name, value } = e.target;

    let newUserDetails = [...userDetails];
    newUserDetails[index] = { ...userDetails[index], [name]: value };
    setUserDetails({ newUserDetails });
  };

  const addInput = () => {
    setUserDetails([...userDetails, { email: "", role: "" }]);
  };

  return (
    userDetails.length >= 0 && (
      <div>
        {[...userDetails].map((el, index) => (
          <form key={index + el} name={el}>
            <div>
              <input
                type="email"
                name="email"
                required
                onChange={(event) => handleChange(event, index)}
                value={el.email}
                style={{ marginTop: 17 }}
                placeholder="Enter Email Address"
              />
            </div>
            <div>
              <input
                type="text"
                name="roles"
                required
                value={el.role}
                style={{ marginTop: 17 }}
                placeholder="Role"
                onChange={(event) => handleChange(event, index)}
              />
            </div>
          </form>
        ))}
        <div>
          <button label="Invite Another?" onClick={addInput}>
            Add input
          </button>
        </div>
        <div>
          <button>Invite</button>
          <button onClick={() => handleCancel()}>Cancel</button>
        </div>
      </div>
    )
  );
};




 ReactDOM.render(
       <InviteUser/>,
       document.getElementById("react")
     );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>

A state is an array of objects that holds email and role:

const [userDetails, setUserDetails] = useState([
    {
      email: "",
      role: ""
    }
  ]);

handleChange function which updates the state by pushing an object (of users inputs values from each individual row) into an array:

  const handleChange = (e, index) => {
    const { name, value } = e.target;

    let newUserDetails = [...userDetails];
    newUserDetails[index] = { ...userDetails[index], [name]: value };
    setUserDetails({ newUserDetails });
  };

and addInput function adds new input fields row:

  const addInput = () => {
    setUserDetails([...userDetails, { email: "", role: "" }]);
  };

And return JSX:

return (
    userDetails.length >= 0 && (
      <InputsContainer>
        {[...userDetails].map((el, index) => (
          <form key={index + el} name={el} onSubmit={handleSubmit}>
            <EmailContainer>
              <input
                type="email"
                name="email"
                required
                onChange={(event) => handleChange(event, index)}
                value={el.email}
                style={{ marginTop: 17 }}
                placeholder="Enter Email Address"
              />
            </EmailContainer>
            <RolesContainer>
              <input
                type="text"
                name="roles"
                required
                value={el.role}
                style={{ marginTop: 17 }}
                placeholder="Role"
                onChange={(event) => handleChange(event, index)}
              />
            </RolesContainer>
          </form>
        ))}
        <InviteButtonContainer>
          <button label="Invite Another?" onClick={addInput}>
            Add input
          </button>
        </InviteButtonContainer>
        <SubmitButtonsContainer>
          <button onClick={(event) => handleSubmit(event)}>Invite</button>
          <button onClick={() => handleCancel()}>Cancel</button>
        </SubmitButtonsContainer>
      </InputsContainer>
    )
  );

What am I doing wrong here?

1 Answer 1

2

You've got two problems:

  1. In setUserDetails you return the array wrapped in an object, instead of just returning the array.
  2. In the roles field you take the value from el.role insted of el.roles.

In addition, since you update the current state, based on a previous one, it's better to use functional updates.

const {useState } = React;

const createNewEntry = () => ({ email: "", role: "" });

const InviteUser = () => {
  const [userDetails, setUserDetails] = useState(() => [createNewEntry()]);

  const handleCancel = () => {
    setUserDetails([createNewEntry()]);
  };

  const handleChange = (e, index) => {
    const { name, value } = e.target;

    setUserDetails(userDetails => {
      const newUserDetails = [...userDetails];
      newUserDetails[index] = { ...userDetails[index], [name]: value };
      return newUserDetails;
    });
  };

  const addInput = () => {
    setUserDetails([...userDetails, createNewEntry()]);
  };

  return (
    userDetails.length >= 0 && (
      <div>
        {[...userDetails].map((el, index) => (
          <form key={index + el} name={el}>
            <div>
              <input
                type="email"
                name="email"
                required
                onChange={(event) => handleChange(event, index)}
                value={el.email}
                style={{ marginTop: 17 }}
                placeholder="Enter Email Address"
              />
            </div>
            <div>
              <input
                type="text"
                name="roles"
                required
                value={el.roles}
                style={{ marginTop: 17 }}
                placeholder="Role"
                onChange={(event) => handleChange(event, index)}
              />
            </div>
          </form>
        ))}
        <div>
          <button label="Invite Another?" onClick={addInput}>
            Add input
          </button>
        </div>
        <div>
          <button>Invite</button>
          <button onClick={() => handleCancel()}>Cancel</button>
        </div>
      </div>
    )
  );
};

ReactDOM.render(
  <InviteUser/>,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>

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

Comments

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.