Christian Townsend
Christian Townsend

Reputation: 301

How to add new input row to table on click?

below is a component of my React project. The basis of the component is a table that displays initially one input row.

import React, { Component } from "react";
import { Navbar, Table, Form } from "react-bootstrap";
import Nav from "./Nav";
import "../client/scss/import.scss";

// import Logo from "./images/logo.svg";

class Import extends Component {
  state = {
    collapseID: ""
  };

  render() {
    return (
      <div>
        <Nav />
        <div className="import">
          <h1>Import New Schedule</h1>
          <div className="importTable">
            <Table className="table table-hover" id="tables">
              <thead className="thead-dark">
                <tr>
                  <th>Queue</th>
                  <th>Start Date</th>
                  <th>End Date</th>
                  <th>Day of Week</th>
                  <th>Time Start</th>
                  <th>Time End</th>
                  <th>Capacity</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>
                    <Form.Control as="select">
                      <option>Veteran Affairs</option>
                      <option>Older Australians</option>
                      <option>Disability Sickness Carers</option>
                      <option>Report Employment Income</option>
                    </Form.Control>
                  </td>
                  <td>
                    <input
                      className="form-control"
                      type="date"
                      value="2011-08-19"
                      id="example-date-input"
                    />
                  </td>
                  <td>
                    <input
                      className="form-control"
                      type="date"
                      value="2011-08-19"
                      id="example-date-input"
                    />
                  </td>
                  <td>
                    <Form.Control as="select">
                      <option>Monday</option>
                      <option>Tuesday</option>
                      <option>Wednesday</option>
                      <option>Thursday</option>
                      <option>Friday</option>
                      <option>Saturday</option>
                      <option>Sunday</option>
                    </Form.Control>
                  </td>
                  <td>
                    <input
                      className="form-control"
                      type="time"
                      value="13:45:00"
                      id="example-time-input"
                    />
                  </td>
                  <td>
                    <input
                      className="form-control"
                      type="time"
                      value="13:45:00"
                      id="example-time-input"
                    />
                  </td>
                  <td>
                    <input
                      className="form-control"
                      type="number"
                      value="0"
                      id="example-number-input"
                    />
                  </td>
                </tr>
              </tbody>
            </Table>
            <button id="addRow">+ Add</button>
          </div>
        </div>
      </div>
    );
  }
}

export default Import;

Towards the bottom you will see the <button id="addRow">+ Add</button> element. Every time this button is clicked, I would like a new row to be appended to the existing table so that additional input fields are visible. Should I be using jQuery to implement this? Could someone please assist in guiding me how to do this? Below is a screenshot how this currently appears on my browser if that helps:

enter image description here

Upvotes: 0

Views: 2067

Answers (2)

Akhil Aravind
Akhil Aravind

Reputation: 6130

If you are looking into a full fledged solution, you can use the below solution. Stackblitz snippet can be found Here

Implementation

We initially created a form structure

  const initialForm = {
      id:1,
      queueType:'',
      startDate:'2011-08-19',
      endDate:'2011-08-19',
      week:'',
      startTime:'13:45:00',
      endTime:'13:45:00',
      capacity:0
    }

On each time the Add is pressed, a copy of the form structure is pushed to the formArray and this form array is iterated.

The setFormValue() function will update the formArray.

 setFormValue = (e, index)=>{
    let {formArray} = this.state;
    formArray[index][e.target.name] = e.target.value;
    this.setState({
      formArray
    })
  }

Update form is rendered in dom ( To see realtime update ), we used

<pre>
{JSON.stringify(this.state.formArray)}
</pre>

The component is implemented as class component.

import React, { Component } from "react";
import { Navbar, Table, Form } from "react-bootstrap";

const initialForm = {
  id:1,
  queueType:'',
  startDate:'2011-08-19',
  endDate:'2011-08-19',
  week:'',
  startTime:'13:45:00',
  endTime:'13:45:00',
  capacity:0
}
export default class Hello extends Component {
  constructor(props){
    super(props);
    this.state = {
      collapseID: "",
      formArray:[
        {
          ...initialForm
        }
      ]
    };
  this.addNewForm = this.addNewForm.bind(this);
  }

  addNewForm = ()=>{
    let newForm = {...initialForm};
    newForm.id = this.state.formArray[this.state.formArray.length -1].id +1;
    this.setState(prevState =>{
      return {
        ...prevState,
        formArray:[...prevState.formArray, newForm]
      }
    })
  }

  setFormValue = (e, index)=>{
    let {formArray} = this.state;
    formArray[index][e.target.name] = e.target.value;
    this.setState({
      formArray
    })
  }

  removeForm=(id)=>{
    const formArray = this.state.formArray.filter(form => form.id != id)
    this.setState({formArray})
  }
  render() {
    return (
      <div>
        <div className="import">
          <h1>Import New Schedule</h1>
          <div className="importTable">
            <Table className="table table-hover" id="tables">
              <thead className="thead-dark">
                <tr>
                  <th>Queue</th>
                  <th>Start Date</th>
                  <th>End Date</th>
                  <th>Day of Week</th>
                  <th>Time Start</th>
                  <th>Time End</th>
                  <th>Capacity</th>
                </tr>
              </thead>
              <tbody>
              {this.state.formArray.map((form,index)=>(
                <tr key={form.id}>
                  <td>
                    <select name="queueType" 
                    defaultValue={form.queueType} 
                    onChange={()=>this.setFormValue(event,index)}>
                      <option>Veteran Affairs</option>
                      <option>Older Australians</option>
                      <option>Disability Sickness Carers</option>
                      <option>Report Employment Income</option>
                    </select>
                  </td>
                  <td>
                    <input
                      className="form-control"
                      type="date"
                      name="startDate"
                      defaultValue={form.startDate} 
                      onChange={()=>this.setFormValue(event,index)}
                      id="example-date-input"
                    />
                  </td>
                  <td>
                    <input
                      className="form-control"
                      type="date"
                      name="endDate"
                      defaultValue={form.endDate} 
                      onChange={()=>this.setFormValue(event,index)}
                      id="example-date-input"
                    />
                  </td>
                  <td>
                    <select name="week" defaultValue={form.week} 
                      onChange={()=>this.setFormValue(event,index)}>
                      <option>Monday</option>
                      <option>Tuesday</option>
                      <option>Wednesday</option>
                      <option>Thursday</option>
                      <option>Friday</option>
                      <option>Saturday</option>
                      <option>Sunday</option>
                    </select>
                  </td>
                  <td>
                    <input
                      className="form-control"
                      type="time"
                      name="startTime"
                      defaultValue={form.startTime} 
                      onChange={()=>this.setFormValue(event,index)}
                      id="example-time-input"
                    />
                  </td>
                  <td>
                    <input
                      className="form-control"
                      type="time"
                      name="endTime"
                      defaultValue={form.endTime} 
                      onChange={()=>this.setFormValue(event,index)}
                      id="example-time-input"
                    />
                  </td>
                  <td>
                    <input
                      className="form-control"
                      type="number"
                      defaultValue={form.capacity} 
                      onChange={()=>this.setFormValue(event,index)}
                      name="capacity"
                      id="example-number-input"
                    />
                  </td>
                  <td>
                    <button type="button" onClick={()=>this.removeForm(form.id)}>- Remove</button>
                  </td>
                </tr>
                ))}
              </tbody>
            </Table>
            <button id="addRow" onClick={this.addNewForm}>+ Add</button>
          </div>
        </div>
        <pre>
        {JSON.stringify(this.state.formArray)}
        </pre>
      </div>
    );
  }
}

Upvotes: 2

Muljayan
Muljayan

Reputation: 3886

Make your table row into a seperate component. Lets call it a Row

// Create a state for the amount of rows you want to view
const [rowCount,setRowCount] = useState(1);

Do the following loop in the render method.

const rowArray = [];

for (let i = 0; i < rowCount; i++) {
  rowArray.push(<Row>)
} 

Insert the rowArray variable insider the return of the render method.

{rowArray}

Your final code should look something like below.

class Import extends Component {
  state = {
    collapseID: "",
    rowCount: 1,
  };

  _addRow = () => {
     const { rowCount } = this.state;
     this.setState(rowCount + 1);
   }

  render() {
     const { rowCount } = this.state;
    const rowArray = [];

    for (let i = 0; i < rowCount; i++) {
      rowArray.push(<Row>)
    } 

    return (
      <div>
        <Nav />
        <div className="import">
          <h1>Import New Schedule</h1>
          <div className="importTable">
            <Table className="table table-hover" id="tables">
              <thead className="thead-dark">
                <tr>
                  <th>Queue</th>
                  <th>Start Date</th>
                  <th>End Date</th>
                  <th>Day of Week</th>
                  <th>Time Start</th>
                  <th>Time End</th>
                  <th>Capacity</th>
                </tr>
              </thead>
              <tbody>
               {rowArray}
              </tbody>
            </Table>
            <button id="addRow" onClick={_addRow}>+ Add</button>
          </div>
        </div>
      </div>
    );
  }
}

export default Import;

Upvotes: 0

Related Questions