3
 my attempt fiddle here ..........

https://jsfiddle.net/techboy0007/j1eas924/

https://i.sstatic.net/KXFot.png

4
  • Hello @vicky, what's your issue here? You need to tell us how we can help you. Commented Mar 8, 2018 at 11:03
  • my issue screenshot here @Arnold Gandarillas i.sstatic.net/KXFot.png Commented Mar 8, 2018 at 11:30
  • I see, I can understand what's your issue. I'll post an answer. Commented Mar 8, 2018 at 13:37
  • By the way for sure it's a good idea to share code in places like jsfiddle but you need to post code here and explain what is not working and how we can help you. Commented Mar 8, 2018 at 14:06

4 Answers 4

26

You can achieve that by playing with react state. In your case you are using nested objects so you need to be carefully when you update them.

It's not a good idea to mutate your state because it can cause easily bugs or an unexpected behavior.

Look closely how the handling functions are working.

Here you have a live demo.

class App extends React.Component {
  state = {
    rows: []
  };
  handleChange = idx => e => {
    const { name, value } = e.target;
    const rows = [...this.state.rows];
    rows[idx] = {
      [name]: value
    };
    this.setState({
      rows
    });
  };
  handleAddRow = () => {
    const item = {
      name: "",
      mobile: ""
    };
    this.setState({
      rows: [...this.state.rows, item]
    });
  };
  handleRemoveRow = () => {
    this.setState({
      rows: this.state.rows.slice(0, -1)
    });
  };
  render() {
    return (
      <div>
        <div className="container">
          <div className="row clearfix">
            <div className="col-md-12 column">
              <table
                className="table table-bordered table-hover"
                id="tab_logic"
              >
                <thead>
                  <tr>
                    <th className="text-center"> # </th>
                    <th className="text-center"> Name </th>
                    <th className="text-center"> Mobile </th>
                  </tr>
                </thead>
                <tbody>
                  {this.state.rows.map((item, idx) => (
                    <tr id="addr0" key={idx}>
                      <td>{idx}</td>
                      <td>
                        <input
                          type="text"
                          name="name"
                          value={this.state.rows[idx].name}
                          onChange={this.handleChange(idx)}
                          className="form-control"
                        />
                      </td>
                      <td>
                        <input
                          type="text"
                          name="mobile"
                          value={this.state.rows[idx].mobile}
                          onChange={this.handleChange(idx)}
                          className="form-control"
                        />
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
              <button
                onClick={this.handleAddRow}
                className="btn btn-default pull-left"
              >
                Add Row
              </button>
              <button
                onClick={this.handleRemoveRow}
                className="pull-right btn btn-default"
              >
                Delete Row
              </button>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));

PD: If I can give you a recommendation I'd say that you need to study a little bit more about react - javascript to move forward, it would help to achieve things like this faster, right now you probably need to focus on understand the basics.

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

5 Comments

You are welcome my friend. One last thing here you can find a good book to start your journey.
@ArnoldGandarillas clean solution. Just one doubt, how to do it if we want delete button for individual rows?
You can use splice method it allows you to remove a single item from an array. I've updated my example supporting that idea. Regards.
Where are the styles located for this ?
it's an external resource you can see it in the left-bottom corner it says bootstrap.min.css
5

Incase someone might be looking for a React hooks version, this is a sample implementation of Arnold's answer:

import React, { useState } from "react";

const App = () => {
  const [rows, setRows] = useState([{}]);
  const collumnsArray = ["name", "id", "mobile", "date", "amount"]; // pass collumns here dynamically

  const handleAddRow = () => {
    const item = {};
    setRows([...rows, item]);
  };

  const postResults = () => {
    console.log(rows); // there you go, do as you please
  };
  const handleRemoveSpecificRow = (idx) => {
    const tempRows = [...rows]; // to avoid  direct state mutation
    tempRows.splice(idx, 1);
    setRows(tempRows);
  };

  const updateState = (e) => {
    let prope = e.target.attributes.collumn.value; // the custom collumn attribute
    let index = e.target.attributes.index.value; // index of state array -rows
    let fieldValue = e.target.value; // value

    const tempRows = [...rows]; // avoid direct state mutation
    const tempObj = rows[index]; // copy state object at index to a temporary object
    tempObj[prope] = fieldValue; // modify temporary object

    // return object to rows` clone
    tempRows[index] = tempObj;
    setRows(tempRows); // update state
  };

  return (
    <div>
      <div className="container">
        <div className="row clearfix">
          <div className="col-md-12 column">
            <table className="table table-bordered table-hover" id="tab_logic">
              <thead>
                <tr>
                  <th className="text-center"> # </th>
                  {collumnsArray.map((collumn, index) => (
                    <th className="text-center" key={index}>
                      {collumn}
                    </th>
                  ))}
                  <th />
                </tr>
              </thead>
              <tbody>
                {rows.map((item, idx) => (
                  <tr key={idx}>
                    <td>{idx + 1}</td>
                    {collumnsArray.map((collumn, index) => (
                      <td key={index}>
                        <input
                          type="text"
                          collumn={collumn}
                          value={rows[idx][collumn]}
                          index={idx}
                          className="form-control"
                          onChange={(e) => updateState(e)}                             
                          
                        />
                      </td>
                    ))}

                    <td>
                      <button
                        className="btn btn-outline-danger btn-sm"
                        onClick={() => handleRemoveSpecificRow(idx)}
                      >
                        Remove
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
            <button onClick={handleAddRow} className="btn btn-primary">
              Add Row
            </button>
            <button
              onClick={postResults}
              className="btn btn-success float-right"
            >
              Save Results
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};

export default App;

2 Comments

Curious about the column property you're using on an input element. That's not a normal prop. Is it supposed to be another prop? Same with index. I'm confused by that. Thanks
@MattoMK It is a custom attribute to help determine the column i.e name or id, dynamically
2

If you want to add/remove rows dynamically you can play with the state, or if you where using Redux you can play with the store.

Here's a simple example using a components local state to add and remove rows:

https://codesandbox.io/s/k302jwn44r

EDIT: fixed mutating state

import React from "react";
import { render } from "react-dom";

const styles = {
  fontFamily: "sans-serif",
  textAlign: "left"
};

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      rows: []
    };
  }

  handleAddRow = () => {
    this.setState((prevState, props) => {
      const row = {content: "hello this is a new row!" };
      return { rows: [...prevState.rows, row] };
    });
  };

  handleRemoveRow = () => {
    this.setState((prevState, props) => {
      return { rows: prevState.rows.slice(1) };
    });
  };

  render() {
    console.log(this.state);
    return (
      <div style={styles}>
        <table>
          <tbody>
            {this.state.rows.map(row => (
              <tr>
                <td>{row.content}</td>
              </tr>
            ))}
            <tr>
              <td className="" onClick={this.handleAddRow}>
                (+)
              </td>
              {Boolean(this.state.rows.length) && (
                <td onClick={this.handleRemoveRow}>(-)</td>
              )}
            </tr>
          </tbody>
        </table>
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));

1 Comment

@ArnoldGandarillas Yup, fixed that
0

Thanks for the answer above. Just a little bit comment on handling of 'handleChange'. Do we need to change the following

    rows[idx] = {
      [name]: value
    };

to the following for saving the data into rows:

const rowInfo = rows[idx];
rowInfo[name] = value;

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.