MERN Stack part one

Setting up the new project
In this blog series we will explore MERN stack by creating a real-world application from beginning to end.

Setting up the react application
It is assumed that Node.js is installed on your machine for this blog. If this is not, please go to https:/nodejs.org/ first and follow your platform's installation instructions.

You can check if node.js is installed on your machine by typing in the below command on the command line. This will print out the Node.js version which is installed on your system.
$ node -v

In the second step we are creating the initial React project by using the create-react-app script. You can execute this script using the npx command, without first installing it on your device. Only execute the order below:
$ npx create-react-app mern-shop-app

Executing this command creates a new project directory mern-shop-app. within this folder you will see the default React project template with all dependencies installed. switch into the newly created folder by using this command.
$ cd mern-shop-app

Start the development web server by typing the following command.
$ npm start

Now you should be able to see the following result in your browser.


Next, we need to add the Bootstrap framework to our project. This is important because we will be designing our user interface using Bootstrap's CSS classes. To attach the library to our project, execute the following command inside the project folder:
$ npm install bootstrap

Then you need to import the CSS file of Bootstrap into the app.js by adding the following code lines:
import "bootstrap/dist/css/bootstrap.min.css";

Setting up the react Router
As the next thing we need to be added to the react router package into the project using the blow command.
$ npm install react-router-dom

After this package installed, we can add the routing configuration in to app.js. first, the following import statement needs to be added:
import { BrowserRouter as Router, Route, Link } from "react-router-dom";

Next, let’s add the JSX code in to a <Router></Router> element:
import React, { Component } from 'react';
import {BrowserRouter as Router, Route, Link} from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";

class App extends Component{
  render(){
    return(
      <Router>
          <div className="container">
              <h2>Shop App</h2>
          </div>
      </Router>
    );
  }
}

export default App;

Inside the <Router> element we’re now ready to add the router configuration inside that element:
<Route path="/" exact component={ItemList}/>
<Route path="/edit/:id" exact component={EditItem}/>
<Route path="/add" exact component={AddItem}/>

 A new <Route> element is added for each path which needs to be added to the application. The path and component attributes are used to add configuration settings for each route. The routing path is set by using the attribute route, and the route is connected to a component by using the component attribute.

As you can see we need to add three routes to our application:
•    /
•    /add
•    /edit/:id

For these three routes we want to connect to three components:
•    ItemList
•    EditItem
•    AddItem

Creating component
First let's create a new directory src / components and create
three new files to create the necessary components in our application:
•    Item-list.component.js:
•    edit-item.component.js:
•    add-item.component.js:

Let’s add a basic React component implementation for each of those components:

Item-list.component.js
import React, {Component} from 'react';

export default class ItemList extends Component{

    render(){
        return(
            <div>
                <p>--Welcome to Item List Component--</p>
            </div>
        )
    }
}

edit-item.component.js:
import React, {Component} from 'react';

export default class EditItem extends Component{

    render(){
        return(
            <div>
                <p>--Welcome to Edit Item Component--</p>
            </div>
        )
    }
}

add-item.component.js:
import React, {Component} from 'react';

export default class AddItem extends Component{

    render(){
        return(
            <div>
                <p>--Welcome to Add Item Component--</p>
            </div>
        )
    }
}

Creating the basic layout & navigation
Next let's add a simple interface and navigation menu to our application.we have installed the bootstrap library before we can now use the CSS classes from Bootstrap to implement our web application's user interface.Extend the App.js code to as follows:

class App extends Component{
  render(){
    return(
      <Router>
          <nav className="navbar navbar-expand-lg navbar-light bg-dark">
              <a className = "navbar-brand" href="https://www.google.com/" target="_blank"><img src={logo} width="30" height="30" alt="google.com"/></a>
              <Link style={{color:"white"}}  to ="/" className="navbar-brand">Amazon Lanka</Link>
              <div className="collpase nav-collapse">
                  <ul className="navbar-nav mr-auto">
                      <li>
                          <Link style={{color:"white"}} to ="/" className="nav-link">Item List</Link>
                      </li>
                      <li>
                          <Link style={{color:"white"}} to ="/edit/:id" className="nav-link">Edit Item</Link>
                      </li>
                      <li>
                          <Link style={{color:"white"}} to ="/add" className="nav-link">Add Item</Link>
                      </li>
                  </ul>
              </div>
          </nav>
  <br/>
  <div className="container">
    <Route path="/" exact component={ItemList}/>
    <Route path="/edit/:id" exact component={EditItem}/>
    <Route path="/add" exact component={AddItem}/>
  </div>
</Router>    );
  }
}
export default App;

Let’s check again what we can see in the Browser:


The navigation bar is displayed with three included menu items (Item List, Edit Item and Add Item). The output of the ItemList component is shown by Default since it was linked to the application's default path.

Clicking on the Add Item link shows the output of addItem component:


Clicking on the Edit Item link shows the output of editItem component




Implement add Item component

In the next step, let's add the implementation of the AddItem component to add-item.component.js script. first, we add a constructor to the component class:

constructor(props) {
    super(props);

    this.state ={
        item_name : '',
        item_description : '',
        item_category : '',
        item_quantity : '',
        item_discount : '',
        item_from : '',
        item_brand :'',
        item_features: '',
        item_image: ''
    }
}

We set the initial state of the component within the constructor, by assigning an object to this.state.The state contains the following properties:
•    item_name
•    item_description
•    item_category
•    item_quantity
•    item_discount
•    item_from
•    item_brand
•    item_features
•    item_image
completed in addition, we need to include methods for updating the state properties:

onChangeItemName(e){
    this.setState({
        item_name :e.target.value
    });
}

onChangeItemDescription(e){
    this.setState({
        item_description :e.target.value
    });
}

onChangeItemCategory(e){
    this.setState({
        item_category :e.target.value
    });
}
onChangeItemQuantity(e){
    this.setState({
        item_quantity :e.target.value
    });
}

onChangeItemDiscount(e){
    this.setState({
        item_discount :e.target.value
    });
}

onChangeItemFrom(e){
    this.setState({
        item_from : e.target.value
    });
}

onChangeItemBrand(e){
    this.setState({
        item_brand : e.target.value
    });
}

onChangeItemFeatures(e){
    this.setState({
        item_features : e.target.value
    });
}

onChangeItemImage(e){
    this.setState({
        item_image : e.target.value
    })
}

A specific approach is required to handle the form submit event that will be implemented to create a new add item.

onSubmit(e){
    e.preventDefault();

    console.log(`Form submitted:`);
    console.log(`item name: ${this.state.item_name}`);
    console.log(`item description: ${this.state.item_description}`);
    console.log(`item category: ${this.state.item_category}`);
    console.log(`item quanity: ${this.state.item_quanity}`);
    console.log(`item discount: ${this.state.item_discount}`);
    console.log(`item from: ${this.state.item_from}`);
    console.log(`item brand: ${this.state.item_brand}`);
    console.log(`item features: ${this.state.item_features}`);
    console.log(`item image: ${this.state.item_image}`);
  
    this.setState({
        item_name : '',
        item_description : '',
        item_category : '',
        item_quanity : '',
        item_discount : '',
        item_from : '',
        item_brand :'',
        item_features: '',
        item_image: ''
    })
}

In this method we will call e.preventDefault to ensure that the default behavior of submitting HTML forms is prevented. Since the back end of our application is not implemented yet we are just printing out to the console what is currently available in the state of the local component. We're actually making sure the form is reset by having the state object reset.

As we are dealing with the state object of the component in the four methods implemented, we need to make sure that we connect these methods to it by adding the following lines of code to the constructor:

this.onChangeItemName = this.onChangeItemName.bind(this);
this.onChangeItemDescription = this.onChangeItemDescription.bind(this);
this.onChangeItemCategory = this.onChangeItemCategory.bind(this);
this.onChangeItemQuantity = this.onChangeItemQuantity.bind(this);
this.onChangeItemDiscount = this.onChangeItemDiscount.bind(this);
this.onChangeItemFrom = this.onChangeItemFrom.bind(this);
this.onChangeItemBrand = this.onChangeItemBrand.bind(this);
this.onChangeItemFeatures = this.onChangeItemFeatures.bind(this);
this.onChangeItemImage = this.onChangeItemImage.bind(this);
this.onSubmit = this.onSubmit.bind(this);

Finally, we need to add the JSX code which is needed to display the form:

render(){
        return(
            <div>
                <form onSubmit={this.onSubmit}>
                    <div className="list-group list-group-flush z-depth-1 rounded">
                    <div className="list-group-item bg-dark d-flex justify-content-start align-items-center py-3">
                            <h4 style={{color:"white"}} > Add Item</h4>
                        </div>
                    </div>
                        <div className="list-group-item">

                            <label>Product name: </label>
                            <input  type="text"
                                    className="form-control"
                                    value ={this.state.item_name}
                                    onChange={this.onChangeItemName}
                                    />

                            <label>Product description: </label>
                            <input type="text"
                                   className="form-control"
                                   value ={this.state.item_description}
                                   onChange={this.onChangeItemDescription}
                                    />

                            <label>Product catogory: </label>
                            <input type="text"
                                   className="form-control"
                                   value ={this.state.item_category}
                                   onChange={this.onChangeItemCategory}
                                    />

                            <label>Product quantity: </label>
                            <input type="text"
                                   className="form-control"
                                   value ={this.state.item_quantity}
                                   onChange={this.onChangeItemQuantity}
                                    />

                            <label>Product Discount: </label>
                            <input type="text"
                                   className="form-control"
                                   value ={this.state.item_discount}
                                   onChange={this.onChangeItemDiscount}
                                    />
                        </div>
                    <br/>
                    <div className="list-group-item">
                            <label>From: </label>
                            <input type="text"
                                   className="form-control"
                                   value ={this.state.item_from}
                                   onChange = {this.onChangeItemFrom}
                                    />

                            <label>Brand: </label>
                            <input type="text"
                                   className="form-control"
                                   value = {this.state.item_brand}
                                   onChange={this.onChangeItemBrand}/>

                            <label>Fatures: </label>
                            <textarea type="text"
                                   className="form-control"
                                   value = {this.state.item_features}
                                   onChange={this.onChangeItemFeatures} />
                        </div>
                    <br/>
                    <div className="list-group-item">
                            <div className="custom-file" style={{marginTop:10}} >
                                <input type="file"
                                       className="custom-file-input"
                                       id="customFileLangHTML"
                                       value = {this.state.item_image}
                                       onChange={this.onChangeItemImage} />
                                <label className="custom-file-label" htmlFor="customFileLangHTML" data-browse="Choose files" >Upload Image</label>

                            </div>
                            <input style={{marginTop:10}} type ="submit" value ="Submit" className = "btn btn-primary"/>
                    </div>
                </form>
            </div>
        )
    }

In the following you can see the complete source code which should now be available in create-todo.component.js:

import React, {Component} from 'react';

export default class AddItem extends Component{

    constructor(props) {
        super(props);

        this.onChangeItemName = this.onChangeItemName.bind(this);
        this.onChangeItemDescription = this.onChangeItemDescription.bind(this);
        this.onChangeItemCategory = this.onChangeItemCategory.bind(this);
        this.onChangeItemQuantity = this.onChangeItemQuantity.bind(this);
        this.onChangeItemDiscount = this.onChangeItemDiscount.bind(this);
        this.onChangeItemFrom = this.onChangeItemFrom.bind(this);
        this.onChangeItemBrand = this.onChangeItemBrand.bind(this);
        this.onChangeItemFeatures = this.onChangeItemFeatures.bind(this);
        this.onChangeItemImage = this.onChangeItemImage.bind(this);
        this.onSubmit = this.onSubmit.bind(this);

        this.state ={
            item_name : '',
            item_description : '',
            item_category : '',
            item_quantity : '',
            item_discount : '',
            item_from : '',
            item_brand :'',
            item_features: '',
            item_image: ''
        }
    }

    onChangeItemName(e){
        this.setState({
            item_name :e.target.value
        });
    }

    onChangeItemDescription(e){
        this.setState({
            item_description :e.target.value
        });
    }

    onChangeItemCategory(e){
        this.setState({
            item_category :e.target.value
        });
    }
    onChangeItemQuantity(e){
        this.setState({
            item_quantity :e.target.value
        });
    }

    onChangeItemDiscount(e){
        this.setState({
            item_discount :e.target.value
        });
    }

    onChangeItemFrom(e){
        this.setState({
            item_from : e.target.value
        });
    }

    onChangeItemBrand(e){
        this.setState({
            item_brand : e.target.value
        });
    }

    onChangeItemFeatures(e){
        this.setState({
            item_features : e.target.value
        });
    }

    onChangeItemImage(e){
        this.setState({
            item_image : e.target.value
        })
    }

    onSubmit(e){
        e.preventDefault();

        console.log(`Form submitted:`);
        console.log(`item name: ${this.state.item_name}`);
        console.log(`item description: ${this.state.item_description}`);
        console.log(`item category: ${this.state.item_category}`);
        console.log(`item quanity: ${this.state.item_quanity}`);
        console.log(`item discount: ${this.state.item_discount}`);
        console.log(`item from: ${this.state.item_from}`);
        console.log(`item brand: ${this.state.item_brand}`);
        console.log(`item features: ${this.state.item_features}`);
        console.log(`item image: ${this.state.item_image}`);

        const newItem = {
            item_name : this.state.item_name,
            item_description : this.state.item_description,
            item_category : this.state.item_category,
            item_quantity : this.state.item_quantity,
            item_discount : this.state.item_discount,
            item_from : this.state.item_from,
            item_brand : this.state.item_brand,
            item_features: this.state.item_features,
            item_image: this.state.item_image
        }

        this.setState({
            item_name : '',
            item_description : '',
            item_category : '',
            item_quanity : '',
            item_discount : '',
            item_from : '',
            item_brand :'',
            item_features: '',
            item_image: ''
        })
    }

    render(){
        return(
            <div>
                <form onSubmit={this.onSubmit}>
                    <div className="list-group list-group-flush z-depth-1 rounded">
                    <div className="list-group-item bg-dark d-flex justify-content-start align-items-center py-3">
                            <h4 style={{color:"white"}} > Add Item</h4>
                        </div>
                    </div>
                        <div className="list-group-item">

                            <label>Product name: </label>
                            <input  type="text"
                                    className="form-control"
                                    value ={this.state.item_name}
                                    onChange={this.onChangeItemName}
                                    />

                            <label>Product description: </label>
                            <input type="text"
                                   className="form-control"
                                   value ={this.state.item_description}
                                   onChange={this.onChangeItemDescription}
                                    />

                            <label>Product catogory: </label>
                            <input type="text"
                                   className="form-control"
                                   value ={this.state.item_category}
                                   onChange={this.onChangeItemCategory}
                                    />

                            <label>Product quantity: </label>
                            <input type="text"
                                   className="form-control"
                                   value ={this.state.item_quantity}
                                   onChange={this.onChangeItemQuantity}
                                    />

                            <label>Product Discount: </label>
                            <input type="text"
                                   className="form-control"
                                   value ={this.state.item_discount}
                                   onChange={this.onChangeItemDiscount}
                                    />
                        </div>
                    <br/>
                    <div className="list-group-item">
                            <label>From: </label>
                            <input type="text"
                                   className="form-control"
                                   value ={this.state.item_from}
                                   onChange = {this.onChangeItemFrom}
                                    />

                            <label>Brand: </label>
                            <input type="text"
                                   className="form-control"
                                   value = {this.state.item_brand}
                                   onChange={this.onChangeItemBrand}/>

                            <label>Fatures: </label>
                            <textarea type="text"
                                   className="form-control"
                                   value = {this.state.item_features}
                                   onChange={this.onChangeItemFeatures} />
                        </div>
                    <br/>
                    <div className="list-group-item">
                            <div className="custom-file" style={{marginTop:10}} >
                                <input type="file"
                                       className="custom-file-input"
                                       id="customFileLangHTML"
                                       value = {this.state.item_image}
                                       onChange={this.onChangeItemImage} />
                                <label className="custom-file-label" htmlFor="customFileLangHTML" data-browse="Choose files" >Upload Image</label>

                            </div>
                            <input style={{marginTop:10}} type ="submit" value ="Submit" className = "btn btn-primary"/>
                    </div>
                </form>
            </div>
        )
    }
}

The result which is displayed in the browser when accessing the /create path should correspond to what you can see in the following:



Comments