0

I'm still beginner to ReactJS and need to build a dynamic table for my work.

In that table, the user can add new lines and can also remove any existing lines.

The problem is, I don't know how to save the values that are typed into the new fields. My onChange function isn't working, I've done several tests, but I'm not able to save the entered values.

Here's my code I put into codesandbox.

Could you tell me what I'm doing wrong to save the entered values? Thank you in advance.

enter image description here

import React from "react";

import "./styles.css";

import List from "./List/List";

const App = () => {
  const [data, setData] = React.useState([
    [
      {
        label: "Property Name",
        field: "propertyName",
        value: ""
      },
      {
        label: "Value",
        field: "value",
        value: ""
      }
    ]
  ]);

  const handleOnChange = (field) => (e) => {
    setData((prev) => ({
      ...prev,
      [field]: e.target.value
    }));
  };

  const addRow = () => {
    setData([
      ...data,
      [
        {
          label: "Property Name",
          field: "propertyName",
          value: ""
        },
        {
          label: "Value",
          field: "value",
          value: ""
        }
      ]
    ]);
  };

  const removeRow = (index) => {
    const _data = [...data];
    _data.splice(index, 1);
    setData(_data);
  };

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <List
        data={data}
        addRow={addRow}
        removeRow={removeRow}
        handleOnChange={handleOnChange}
      />
    </div>
  );
};

export default App;

import React from "react";

import AddCircleIcon from "@material-ui/icons/AddCircle";
import RemoveCircleIcon from "@material-ui/icons/RemoveCircle";
import TextField from "@material-ui/core/TextField";

import "./styles.scss";

const List = ({ data, handleOnChange, addRow, removeRow }) => {
  return (
    <div className="container">
      {data.map((items, index) => (
        <div key={index} className="content">
          <div className="content-row">
            {items.map((item, index) => (
              <TextField
                key={index}
                label={item.label}
                value={item.value}
                onChange={handleOnChange(index)}
                variant="outlined"
              />
            ))}
          </div>
          <div>
            <AddCircleIcon onClick={addRow} />
            {data.length > 1 && (
              <RemoveCircleIcon onClick={() => removeRow(index)} />
            )}
          </div>
        </div>
      ))}
    </div>
  );
};

export default List;

1 Answer 1

1

Good that you shared the code. There are several issues with your code. I have an updated code placed under this URL,

https://codesandbox.io/s/reverent-mclean-hfyzs

Below are the problems,

  1. Your data structure is an array of arrays and your onchange event doesn't respect that.
  2. You have no property available [name/id] to identify a textbox when you change the value.

I had to add a name property to each textbox and design it like a 2D array so any textbox will have a unique name.

I had to map through the data array and find the node where I have to update the value and set the new value as the new state when any textbox changes.

I have added a console.log while adding a row so you can see the current state.

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.