TechSavy
TechSavy

Reputation: 1340

Add row to existing table dynamically in ReactJS

I am learning ReactJS.

I have pre-existing table rendered which contains thead and only 1 row by default. Now on button click, I want to append a row everytime the button click, but the max rows appended should not be greater than 4.

Here is my code:

import React, { Component } from "react";
import Sidebar from "../Home/Sidebar";
import axios from "axios";
import $ from "jquery";
import { isDivisibleBy100 } from "../utils/utility";
import { Chart } from "react-charts";

class Strategy extends Component {
  state = {
    Price: [],
    chart_data: [],
    loadData: true,
    unit: parseFloat(0),
    loadUnit: true,

  };

  componentDidMount() {
    this.getPriceList();
  }

  getPriceList() {
    axios.get("http://localhost:8000/listprice/").then(res => {
      if (res.data.result === 1) {
        this.setState({ Price: res.data.data });
      }
    });
  }


  appendRow(event) {
    var rel = event.target.getAttribute("rel");
    rel = parseInt(rel) + 1;
    console.log(rel);
    var addRow = (
      <tr>
        <td>
          <input type="text" id={`select-type` + rel} />
        </td>
        <td>
          <input type="text" id={`select-position` + rel} />
        </td>
      </tr>
    );
    $(".table tbody").append(appRow);
  }

  render() {
    return (
      <div className="container container_padding">
        <div className="row">
          <Sidebar />
          <div className="col-md-9 col-sm-9 col-xs-12 white-box">
            <div className="col-sm-12">
              <h3 className="col-sm-4" style={{ padding: "0px" }}>
                Strategy Plan:
              </h3>
              <div className="col-sm-7" />
              <div className="col-sm-1" style={{ marginTop: "15px" }}>
                <button
                  rel="1"
                  type="button"
                  id="addbtn"
                  className="btn btn-circle"
                  onClick={this.appendRow}
                >
                  <i className="fa fa-plus" />
                </button>
              </div>
            </div>
            <div className="col-sm-12 a">
              <div className="table-responsive">
                <table className="table table-bordered">
                  <thead>
                    <tr>
                      <td>#</td>
                      <td>Type</td>
                      <td>Position</td>
                      <td>Price</td>
                      <td>Number</td>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>1</td>
                      <td>
                        <select
                          className="form-control"
                          name="select-type"
                          id="select-type"
                        >
                          <option value="select">Select</option>
                          <option value="one">1</option>
                          <option value="two">2</option>
                        </select>
                      </td>
                      <td>
                        <select
                          className="form-control"
                          name="select-position"
                          id="select-position"
                        >
                          <option value="select">Select</option>
                          <option value="a">A</option>
                          <option value="b">B</option>
                        </select>
                      </td>
                      <td>
                        <select
                          className="form-control"
                          name="price-list"
                          id="price-list"
                          onChange={event =>
                            this.handlePriceChange(event)
                          }
                        >
                          <option value="select">Select</option>
                          {this.state.Price.map(p => (
                            <option
                              value={p.pprice}
                              key={p.price}
                            >
                              {p.price}
                            </option>
                          ))}
                        </select>
                      </td>
                      <td style={{ width: "180px" }}>
                        <input
                          id="input-number"
                          type="text"
                          className="form-control"
                          defaultValue="1"
                        />
                      </td>
                    </tr>


                  </tbody>
                </table>
              </div>
            </div>
            <div className="col-sm-12">
              <button
                className="btn"
                onClick={() => this.handleClick()}
              >
                Calculate
              </button>
            </div>

            {this.state.loadData ? (
              ""
            ) : (
              <div
                style={{
                  width: "600px",
                  height: "300px",
                  marginTop: "35px",
                  marginLeft: "25px",
                  marginBottom: "10px"
                }}
              >
                <Chart
                  data={this.state.chart_data}
                  series={{ type: "line" }}
                  axes={[
                    { primary: true, type: "linear", position: "bottom" },
                    { type: "linear", position: "left" }
                  ]}
                  primaryCursor
                  secondaryCursor
                  tooltip
                />
              </div>
            )}
          </div>
        </div>
      </div>
    );
  }
}

export default Strategy;

The appendRow function is not appending the row.

What am I missing? Is there any better way to achieve this?

Please suggest.

Thanks in advance

Upvotes: 2

Views: 21041

Answers (2)

gilbert-v
gilbert-v

Reputation: 1305

Constructor method:

constructor(props) {
  super(props)
  this.state = {rows: []};
}

Inside your appendRow method, instead of adding the tr directly to your tbody, add the tr to the rows state:

appendRow(event) {
  var rel = event.target.getAttribute("rel");
  rel = parseInt(rel) + 1;

  var joined = this.state.rows.concat(
  <tr>
    <td>
      <input type="text" id={`select-type` + rel} />
    </td>
    <td>
      <input type="text" id={`select-position` + rel} />
    </td>
  </tr>
  );
  this.setState({ rows: joined })
}

Inside your render method, just put the array in. It will be re-rendered whenever setState is called:

render() {
  ...
  return (
     ...
     <button
       rel="1"
       type="button"
       id="addbtn"
       className="btn btn-circle"
       onClick={this.appendRow}>
       <i className="fa fa-plus" />
     </button>
     ...
     <tbody>
       {this.state.rows}
     </tbody>
     ...
  )
  ...
}

Upvotes: 1

Shiva Pandey
Shiva Pandey

Reputation: 655

You are using jquery and directly handling real DOM. With React we use Virtual DOM and don't manipulate the real DOM. Unlike Jquery, in react you don't have to worry about handling UI. Your concern should be handling the data properly, leave the UI updates to React. You haven't provided the Table Component information here. So, I would give you a code sample which does exactly what you want to achieve. For the button you can place it where it's needed within this component.

import React from "react";

class Table extends React.Component {
  state = {
    data: []
  };
  appendChild = () => {
    let { data } = this.state;
    data.push(data.length); // data.length is one more than actual length since array starts from 0.
    // Every time you call append row it adds new element to this array. 
    // You can also add objects here and use that to create row if you want.
    this.setState({data});
  };
  render() {
    return (
      <table>
        <thead>
          <th>Type</th>
          <th>Position</th>
        </thead>
        <tbody>
          {this.state.data.map(id => (
            <Row id = {id} />
          ))}
        </tbody>
      </table>
    );
  }
}

const Row = ({ id }) => (
  <tr>
    <td>
      <input type="text" id={`select-type-${id}`} />
    </td>
    <td>
      <input type="text" id={`select-position-${id}`} />
    </td>
  </tr>
);

Upvotes: 3

Related Questions