Web applications in React, Bootstrap, MongoDB, Express/Create a React app with Bootstrap that performs read, create, update, delete operations on a MongoDB database via a Node Express web server

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Now we will create the Front end in React-Bootstrap that connects to the Node Express web server and through Rest API acts on the MongoDB database with GET, POST, PUT, DELETE operations on the items in a warehouse:

Schermata programma.png
  • 1) In the Documents folder open a terminal and type:
npx create-react-app items-app


  • 2) In the items-app folder open a terminal and type to install the Bootstrap css framework:
npm install react-bootstrap bootstrap@5.1.3
  • 3) Replace the App.js file with the following:
//App.js
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Items from './Componenti/Items';


class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
       baseUrl : 'http://localhost:3000/',
    };
   
  }
  render() {
    return (
      <div className="container-fluid">
        <title>Manage Items</title>

        <h1 className="text-center text-primary">Manage Items</h1>
        <h2 className="text-center text-secondary">with React, Bootstrap, MongoDB, Express</h2>

        <Items baseUrl={this.state.baseUrl} />


      </div>

    );
  }
}
export default App;


  • 4) Create a Components sub folder in which to insert the following files:
//items.js
import 'bootstrap/dist/css/bootstrap.min.css';
import Tabella from './Tabella';
import React from 'react';
import ModalView from './ModalView';

class Items extends React.Component
{
  constructor(props)
  {
    super(props);
    this.state = {
      inputID: "",
      inputName: "",
      inputQuantity: "",
      inputMeasure: "",
      show: false,
      message: ''
    };
    this.handleClickNuovo = this.handleClickNuovo.bind(this);
    this.handleClickSalva = this.handleClickSalva.bind(this);
    this.handleChangeName = this.handleChangeName.bind(this);
    this.handleChangeQuantity = this.handleChangeQuantity.bind(this);
    this.handleChangeMeasure = this.handleChangeMeasure.bind(this);
    this.handleClose = this.handleClose.bind(this);

  }
  
  handleChangeName(event)
  {
    this.setState({
      inputName: event.target.value,
    });
  }

  handleChangeQuantity(event)
  {
    this.setState({
      inputQuantity: event.target.value,
    });
  }

  handleChangeMeasure(event)
  {
    this.setState({
      inputMeasure: event.target.value,
    });
  }

  handleClickNuovo(event)
  {

    this.setState({
      inputID: "",
      inputName: "",
      inputQuantity: "",
      inputMeasure: "",
      show: false,
    });
  }

  handleClickSalva(event)
  {

    if (this.state.inputName === "" ||
      this.state.inputQuantity === "" ||
      this.state.inputMeasure === "" )
    {
      this.setState({
        show: true,
        message: 'Tutti i campi devono essere compilati! '
      })
    }

    else if (isNaN(parseFloat(this.state.inputQuantity)))
    {
      this.setState({
        show: true,
        message: 'Quantity is a number!'
      })
    } else
    {

      const requestOptions = {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ 
          name: this.state.inputName,
          quantity: this.state.inputQuantity,
          measure: this.state.inputMeasure
         })
    };

    fetch(this.props.baseUrl + 'items', requestOptions)
        .then(() => console.log('Item created'))
        .catch(err => {
          console.error(err);
        });
      
        this.setState({
          show: true,
          message: 'Item created!'
        })
     
    }
    
  }

  handleClose(event)
  {

    this.setState({
      show: false,
    });
  }

  render()
  {
    return (
      <div class="row">
        <div className="col-md-12">
          <div className="card" >
            <div className="card-body">
              <h5 className="card-title">Item:</h5>
              <div className="input-group mb-3">
              
                <span className="input-group-text">Item name:</span>
                <input

                  type="text"
                  className="form-control"
                  value={this.state.inputName}
                  onChange={this.handleChangeName}
                />
                <span className="input-group-text">Quantity:</span>
                <input

                  type="text"
                  className="form-control"
                  value={this.state.inputQuantity}
                  onChange={this.handleChangeQuantity}
                />
                <span className="input-group-text">Measure:</span>
                <input

                  type="text"
                  className="form-control"
                  value={this.state.inputMeasure}
                  onChange={this.handleChangeMeasure}
                />

              </div>


              <button onClick={this.handleClickNuovo} className="btn btn-primary">
                 New
              </button>
              <button onClick={this.handleClickSalva} className="btn btn-secondary">
                 Save
              </button>
              <button  className="btn btn-success">
                 Update
              </button>

              <ModalView
                message={this.state.message} show={this.state.show} handleClose={this.handleClose}
              />
            </div>
          </div>
          <Tabella baseUrl={this.props.baseUrl} />

        </div>

      </div>

    );
  }
}

export default Items;
//Tabella.js
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import ModalViewEdit from './ModalViewEdit';

class Tabella extends React.Component
{
  constructor(props)
  {
    super(props);
    this.state = {
      rows: [],
      show: false,
      editRow:{}
    }

    this.handleDelete = this.handleDelete.bind(this);
    this.handleEdit = this.handleEdit.bind(this);
    this.handleClose = this.handleClose.bind(this);
    this.handleClickEvent = this.handleClickEvent.bind(this);
    this.handleClick = this.handleClick.bind(this);

  }

  componentDidMount()
  {
    this.handleClick();
    document.addEventListener('click', this.handleClickEvent)
  }

  componentWillUnmount()
  {
    document.removeEventListener('click', this.handleClickEvent)
  }

  handleClickEvent(event)
  {
    this.handleClick();
  }

  handleClick()
  {
    fetch(this.props.baseUrl + 'items').then(function (data)
    {
      return data.json();
    }).then(json =>
    {
      this.setState({
        rows: json.map((row) =>
          <tr  >
            <th scope="row"  >{row._id}</th>
            <td>{row.name}</td>
            <td>{row.quantity}</td>
            <td>{row.measure}</td>
            <td ><button id={row._id} onClick={this.handleEdit} className="btn btn-info">
               Edit
            </button></td>
            <td ><button id={row._id} onClick={this.handleDelete} className="btn btn-danger">
               Delete
            </button></td>

          </tr>),

      });

    });

  }


  handleDelete = (e) =>
  {

    const key = e.currentTarget.getAttribute("id");

    fetch(this.props.baseUrl + 'items/' + key,
      {
        method: 'DELETE',

      })
      .then(() => console.log('Item deleted: ' + key))
      .catch(err =>
      {
        console.error(err);
      });

    this.handleClick();

  }

  handleEdit = (e) =>
  {
    const key = e.currentTarget.getAttribute("id");

    fetch(this.props.baseUrl + 'items/' +key).then(function (data)
    {
      return data.json();
    }).then(json =>
    {
      this.setState({
        editRow: json,
        show:true,
      });

    });
  }


  handleClose(event)
  {

    this.setState({
      show: false,
      editRow:{}
    });
  }

  render()
  {

    return (

      <>
        <table className="table table-striped" >
          <thead>
            <tr>
              <th scope="col">ID</th>
              <th scope="col">Name</th>
              <th scope="col">Quantity</th>
              <th scope="col">Measure</th>
            </tr>
          </thead>
          <tbody>
            {this.state.rows}
          </tbody>
        </table>
        
        {this.state.show && <ModalViewEdit
          baseUrl={this.props.baseUrl} editRow={this.state.editRow} show={this.state.show} handleClose={this.handleClose}
        />}
      </>
    );
  }
}
export default Tabella;


  • 5) In the terminal type:
npm start


and use the program.