2

i have a table where the table has many rows of data. enter image description here

my table has function which can add multiple row to handle multiple input. so far this function to add multiple rows in my table is works. when i click button to generate multiple empty rows. this is example code that i used before. this code just record lasted input.

const [newInputRows, setNewInputRows] = useState([])
const handleChangeNewRows = (event) => {
    setNewRows({...newInputRows, [event.target.name] : event.target.value})
    console.log(newInputRows)
  }

this bellow part of return. this is my code to generate new empty rows::

const newRows = [0, 1, 2, 3, 4]
        <tbody>
              {
                insertRows && newRows.map(rows =>
                  <tr key={rows} id={rows}>
                    <td style={setStyle("20px")}></td>
                    {
                      _header.map((column,idc) => column === '_id' ? null : <td key={idc} className="input"><InputRows type="text" name={column} onChange={handleChangeNewRows}/></td>)
                    }
                  </tr>
                 )
               }
        </tbody>

as you can see, all of the rows has multiple input with same(single) name. my question is how to handle form input with multiple values in a single input name. because this form will send into backend where the database has 2 field countryCode and Country name. i want to make this form send to backend to be an array of object like this bellow:

[
{countryCode: "A", countryName: "countryA"},
{countryCode: "B", countryName: "countryB"},
{countryCode: "C", countryName: "countryC"}
]

how to handle this in reactjs?

5
  • Generate a GUID to associate with each row of data/inputs. Can you share a Minimal, Complete, and Reproducible Code Example for what you've tried already? Commented Aug 2, 2021 at 5:50
  • for the GUI you can see the img link above @DrewReese Commented Aug 2, 2021 at 6:10
  • GUID, not GUI, I'm referring to a Globally Unique Identifier, as in, an id to uniquely identify a row for which you want to update state data for since all the inputs share name attributes. If you don't have any row ids, I can help improve your code if you share the MCR code example in your question. Commented Aug 2, 2021 at 6:26
  • ohh okay, let me give an example to my posting Commented Aug 2, 2021 at 6:33
  • i just put my code that i used to generate new row. @DrewReese Commented Aug 2, 2021 at 6:48

2 Answers 2

1

An issue I see is with how you handle updating row data, you are changing the state invariant from array to object and you've no way to uniquely identify the row of data you want to update.

  1. I suggest first create a callback to add an id to each row new data element.

    import { v4 as uuidV4 } from "uuid";
    
    ...
    
    const [rowData, setRowData] = useState([]);
    
    const addRow = () =>
      setRowData((rowData) =>
        rowData.concat({
          id: uuidV4(),
          countryCode: "",
          countryName: ""
        })
      );
    
  2. Use a curried change handler to close over in scope a row id, and use a functional state update to shallow copy the previous state.

    const changeHandler = (rowId) => (e) => {
      const { name, value } = e.target;
      setRowData((rowData) =>
        rowData.map((data) =>
          data.id === rowId
            ? {
                ...data,
                [name]: value
              }
            : data
        )
      );
    };
    
  3. Map the row data and attach the change handlers.

    {rowData.map((data) => (
      <tr key={data.id}>
        <td>
          <input
            name="countryCode"
            value={data.countryCode}
            onChange={changeHandler(data.id)}
          />
        </td>
        <td>
          <input
            name="countryName"
            value={data.countryName}
            onChange={changeHandler(data.id)}
          />
        </td>
      </tr>
    ))}
    

Demo

Edit how-to-handle-input-form-with-single-name-input-that-has-many-value

enter image description here

[
  {countryCode: "A", countryName: "countryA"},
  {countryCode: "B", countryName: "countryB"},
  {countryCode: "C", countryName: "countryC"}
]
Sign up to request clarification or add additional context in comments.

5 Comments

ig got new problems with event onChange, this code is works. now mycode could save into database. but the last row and the last character that i type in input can't captured. let me give an example. if i type "countryC" my code just capture "country" the letter C is gone. i don't know why
@rikiyudha Are you enqueueing a state update and then immediately trying to use the state to do something else? Remember that React state updates are asynchronously processed. It seems you are using the state from the current render cycle and not what it will be in the next render cycle.
@rikiyudha Have you still an issue to resolve?
for input type text i have no issue but i have an issue with input checkbox type and radio input type now @Drew Reese
@rikiyudha I see. Normally you would/should post a new question for any new issues when the current question is resolved. My guess here is that you need to handle the checked property of the onChange event. Can you add the new relevant details regarding checkbox/radio inputs?
0

The output is what you want

import React, { useState } from "react";
import "./styles.css";

const App = () => {
  const [list, setList] = useState([]);
  const handleClick = () => {
    list.splice(0, list.length);
    const inputs = document.getElementsByTagName("input");
    for (var i = 0; i < inputs.length; i++) {
      if (inputs[i].name === "countryName") {
        list.push({
          countryCode: inputs[i - 1].value,
          countryName: inputs[i].value
        });
        setList(list);
      }
    }
    console.log("list: ", JSON.stringify(list));
  };
  return (
    <>
      <table>
        <tr>
          <td>
            <input name="countryCode" />
          </td>
          <td>
            <input name="countryName" />
          </td>
        </tr>
        <tr>
          <td>
            <input name="countryCode" />
          </td>
          <td>
            <input name="countryName" />
          </td>
        </tr>
        <tr>
          <td>
            <input name="countryCode" />
          </td>
          <td>
            <input name="countryName" />
          </td>
        </tr>
      </table>
      <button onClick={handleClick}>click</button>
    </>
  );
};
export default App;

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.