Responsive Bootstrap application with React and Node

We will include and modularize our Bootstrap application that we have developed so far. In this application, we can see the static user profile raising helpdesk tickets online and rendering React components server-side. We have not used any database so we are storing our tickets in the browser's local storage. We can see the submission of the tickets in view tickets.

For your reference, I have included the Mongodb configuration and connection setup with db in the code snippet that you can get along with this book. Also, I have included the mongoose schema for the Add Ticket Form so you can play with them.

First, let's open the entry point of the script file index.js in the src folder and import the React modules.

import React from 'react'; 
import ReactDOM from 'react-dom'; 
import { Router, Route, Link, IndexRoute,IndexLink, browserHistory } 
from 'react-router' 

In version 15.4.0, React and ReactDOM are separated into different packages. React.render() is deprecated in favor of ReactDOM.render() in React 0.14, and the developers have also removed DOM-specific APIs from React completely in React 15.

In React 15.4.0, they have finally moved ReactDOM implementation to the ReactDOM package. The React package will now contain only renderer-agnostic code such as React.Component and React.createElement().

Go to this blog to get the latest updates about React:

https://facebook.github.io/react/blog/

Now we need to import the Bootstrap, CSS, and JS files:

import '../css/custom.css'; 
import '../vendor/css/base.css'; 
import '../vendor/css/bootstrap.min.css'; 
import '../vendor/js/bootstrap.min.js'; 

Now let's start the server with the following command and see if our code and configuration can build or not:

nodemon start

It monitors the changes in your application files and restarts the server.

Or if we have not installed nodemon then the command should be:

node server.js

Responsive Bootstrap application with React and Node

The server is started in webpack to build your code bundle to the server client browser. If everything goes smoothly, you can get this info when the build is complete:

Responsive Bootstrap application with React and Node

For now our page is blank. There is nothing to show because we have not included any component in our page yet.

Let's create one component for Bootstrap navigation with the name navbar.js in the component folder.

module.exports.PageLayout = React.createClass({ 
}) 

module.exports is a special object in Node.js and is included in every JS file. It exposes your functions, variables, and anything you have written inside module.exports as a module that makes your code reusable and easy to share.

Let's add our Bootstrap navigation component inside this with the container layout to render the page content:

render: function() { 
    return ( 
        <main> 
        <div className="navbar navbar-default navbar-static-top"
        role="navigation"> 
            <div className="container"> 
                <div className="navbar-header"> 
                    <button type="button" className="navbar-toggle"
                    data-toggle="collapse" data-target=".navbar-collapse"> 
                    <span className="sr-only">Toggle navigation</span> 
                    <span className="icon-bar"></span> 
                    <span className="icon-bar"></span> 
                    <span className="icon-bar"></span> 
                    </button> 
                    <Link className="navbar-brand" to="/">EIS</Link> 
                </div> 
            <div className="navbar-collapse collapse"> 
            <ul className="nav navbar-nav"> 
            <li><IndexLink activeClassName="active" to="/">
            Home</IndexLink></li> 
            <li><Link to="/edit" activeClassName="active">
            Edit Profile</Link></li> 
            <li className="dropdown"> 
                <Link to="#" className="dropdown-toggle"
                data-toggle="dropdown">Help Desk <b className="caret">
                </b></Link> 
            <ul className="dropdown-menu"> 
            <li><Link to="/alltickets">View Tickets</Link></li> 
            <li><Link to="/newticket">New Ticket</Link></li> 
            </ul> 
            </li> 
            </ul> 
        </div> 
    </div> 
</div> 

Our page navigation container ends here.

Here we are starting the main container of the page where we can render the page content by using props:

<div className="container"> 
    <h1>Welcome to EIS</h1> 
    <hr/> 
    <div className="row"> 
    <div className="col-md-12 col-lg-12"> 
    {this.props.children} 
    </div> 
    </div> 
    </div> 
</main> 
); 
}  

Let's continue to add the home page content and prepare our first layout:

const RightSection = React.createClass({ 
    render: function() { 
        return (<div className="col-sm-9 profile-desc" id="main">  
        <div className="results">  
        <PageTitle/> 
        <HomePageContent/> 
        </div> 
        </div>) 
    } 
}) 
// include Left section content in ColumnLeft component with the wrapper of bootstrap responsive classes classes    

const ColumnLeft = React.createClass({ 
    render: function() { 
        return ( 
        ) 
    } 
}) 
const LeftSection = React.createClass({ 
    render: function() { 
        return (  
        //Left section content          
        ) 
    } 
}) 
const TwoColumnLayout = React.createClass({ 
    render: function() { 
        return ( 
            <div> 
            <ColumnLeft/> 
            <RightSection/> 
            </div> 
        ) 
    } 
})  

Here we are including the page title and home page content in this component:

const PageTitle = React.createClass({ 
    render: function() { 
        return ( 
            <h2>//page content</h2> 
        ); 
    } 
}); 
const HomePageContent = React.createClass({ 
    render: function() { 
        return ( 
            <p>//page content</p> 
        ); 
    } 
}); 

Now we need to configure the routing to render the component in the UI:

ReactDOM.render(( 
    <Router history={browserHistory}> 
    <Route path="/" component={PageLayout}> 
    <IndexRoute component={TwoColumnLayout}/> 
    </Route> 
    </Router> 
), document.getElementById('root')); 

We need to repeat the same flow with the other components and pages:

Responsive Bootstrap application with React and Node

Our page looks great; we have successfully integrated our first page with Node.js.

Let's move to our main component and add a ticket in the help desk section.

Create a file with the name of addTicketForm.js and include the following code:

import React from 'react'; 
import ReactDOM from 'react-dom'; 

Including the React module is important in every file where we have React code:

var max_Char='140'; 
var style = {color: "#ffaaaa"}; 
 
module.exports.AddTicket = React.createClass({ 
    getInitialState: function() { 
        return {value: '', char_Left: max_Char}; 
    }, 
    handleChange: function(event) { 
        var input = event.target.value; 
        this.setState({value: input.substr(0, max_Char),char_Left:
        max_Char - input.length}); 
        if (input.length == max_Char){ 
            alert("You have reached the max limit") 
        } 
    }, 

Tip

In the preceding code, we are controlling the textarea component with the same code we created in Chapter 5, jQuery Bootstrap Component with React.

handleSubmitEvent: function (event) { 
    event.preventDefault(); 
    
var values   = { 
    date: new Date(), 
    email: this.refs.email.value.trim(), 
    issueType: this.refs.issueType.value, 
    department: this.refs.department.value, 
    comment: this.state.value 
}; 
this.props.addTicketList(values); 
localStorage.setItem('Ticket', JSON.stringify(values)); 
}, 

Before we were just displaying in the AddTicket UI after submitting the form. Now we are using the local storage to save the tickets.

render: function() { 
    return ( 
        <form onSubmit={this.handleSubmitEvent}> 

Here you need to put in the other form elements that we added before:

<div className="form-group"> 
    <label htmlFor="comments">Comments <span style={style}>*</span>
    </label>(<span>{this.state.char_Left}</span> characters left) 
        <textarea className="form-control" value={this.state.value} 
        maxLength={max_Char} ref="comments" onChange={this.handleChange} /> 
   </div> 
   <div className="btn-group"> 
       <button type="submit" className="btn btn-primary">Submit</button> 
       <button type="reset" className="btn btn-link">cancel</button> 
   </div> 
   </form> 
   ); 
} 
}); 

Next we need to create addTicketList.js where we are wrapping this JSX form into the component:

<AddTicket addTicketList={this.addTicketList} /> 

Also we need to create listView.js to display the list which after the user submits at the same time:

import { AddTicket } from "./addTicketForm.js";
import { List } from "./listView.js";

Here we have imported the AddTicket module that we created before and created another module, addTicketForm, to manage the form state for the update:

module.exports.AddTicketsForm = React.createClass({ 
    getInitialState: function () { 
        return { 
            list: {} 
        }; 
    }, 
    updateList: function (newList) { 
        this.setState({ 
            list: newList 
        }); 
    }, 
    addTicketList: function (item) { 
    var list = this.state.list; 
    list[item] = item; 
    this.updateList(list); 
    }, 
    render: function () { 
        var items = this.state.list; 
    return ( 
        <div className="container"> 
        <div className="row"> 
        <div className="col-sm-6"> 
            <List items={items} /> 
            <AddTicket addTicketList={this.addTicketList} /> 
        </div> 
        </div> 
        </div> 
    ); 

In the render method, we are passing the form and list items into the component:

    } 
}); 
listView.js 
import { ListPanel } from "./ListUI.js"; 

In the ListPanel, we have actual JSX code that renders the tickets to the UI after the user submits and creates the module that we have included in addTicketList.js:

module.exports.List = React.createClass({ 
    getListOfIds: function (items) { 
    return Object.keys(items); 
    }, 
    createListElements: function (items) { 
        var item; 
        return ( 
            this 
                .getListOfIds(items) 
                .map(function createListItemElement(itemId,id) { 
                    item = items[itemId]; 
                    return (<ListPanel key={id} item={item} />); 
                    }.bind(this)) 
               .reverse() 
        ); 
    }, 
    render: function () { 
        var items = this.props.items; 
        var listItemElements = this.createListElements(items); 
        return ( 
            <div className={listItemElements.length > 0 ? "":""}> 
            {listItemElements.length > 0 ? listItemElements : ""} 

Here we are rendering the listItemElements into the DOM:

        </div> 
    ); 
    } 
}); 

Now let's create ListUI.js, the last module, which will complete the functionality of the form component:

module.exports.ListPanel =  
React.createClass({ 
    render: function () { 
        var item = this.props.item; 
    return ( 
        <div className="panel panel-default"> 
        <div className="panel-body"> 
        Emailid: {item.email}<br/> 
        IssueType: {item.issueType}<br/> 
        IssueType: {item.department}<br/> 
        Message: {item.comment} 
        </div> 
        <div className="panel-footer"> 
       {item.date.toString()} 
       </div> 
       </div> 
    ); 
    } 
}); 

Let's see how the output in the browser looks.

Make sure you have included the following code in your router with the URL:

<Route path="/newticket" component={AddTicketsForm} />

Observe the following screenshot:

Responsive Bootstrap application with React and Node

Looks good. Now let's fill in this form, submit it, and view the output:

Responsive Bootstrap application with React and Node

That's awesome; our form works as expected.

You can also see the submit Ticket in the browser's local storage with the  Key and Value format of the JSON notation:

Developer Tools > Application > Storage > Local Storage

Observe the following screenshot:

Responsive Bootstrap application with React and Node

Now we need to get this JSON Ticket from the local storage and display it to the user in the View Tickets section.

Let's create another module to get the tickets and render it into the Bootstrap responsive table. The file

allTickets.js will look as follows:

module.exports.allTickets = React.createClass({ 
    getInitialState: function() { 
        return { 
            value :JSON.parse(localStorage.getItem( 'Ticket' )) || 1}; 
        }, 

In the initial state of the component, we are using localStorage.getItem to get the tickets and parse them into the JSON to set the state:

getListOfIds: function (tickets) { 
    return Object.keys(tickets); 
    }, 
    createListElements: function (tickets) { 
    var ticket; 
    return ( 
        this 
        .getListOfIds(tickets) 
        .map(function createListItemElement(ticket,id) { 
        ticket = tickets[ticket]; 
        return (<ticketTable key={id} ticket={ticket}/>) 
        }.bind(this)) 
    ); 
}, 

Using the same approach we used in adding the ticket, we are mapping the ticket key and the value into the React component by props:

render: function() { 
    var ticket = this.state.value;

In the render method, we are assigning the state value into the ticket variable that we are passing into the createListElements function:

var listItemElements = this.createListElements(ticket); 
return ( 
    <div> 
        <div className={listItemElements.length > 0 ? "":"bg-info"}> 
            {listItemElements.length > 0 ? "" : "You have not raised any ticket yet."} 

We are using the JavaScript ternary operator to check if we have any ticket or, if not, to display the message in the UI.

</div> 
    <table className="table table-striped table-responsive"> 
        <thead> 
            <tr> 
                <th>Date</th> 
                <th>Email ID</th> 
                <th>Issue Type</th> 
                <th>Department</th> 
                <th>Message</th> 
            </tr> 
        </thead> 
        <tbody> 
        <tr> 
            {listItemElements.length > 0 ? listItemElements : ""} 
        </tr> 
        </tbody> 
    </table> 
</div> 
// In the preceding code, we are creating the table header and appending the ticket list items.
   ); 
   } 
}); 

Now we need to create the component that includes the <td> and inherits the ticket data. ticketTable.js will look as follows:

module.exports.ticketTable = React.createClass({ 
    render: function () { 
        var ticket = this.props.ticket; 
        return ( 
            <td>{ticket}</td> 
        ); 
    } 
}); 

And also we need to import this module in the allTickets.js file:

const table = require("./ticketTable.js"); 

You may notice that I have used the const object rather than using import. You can also use var instead. const refers to constants; they are block-scoped, much like variables. The value of a constant cannot change and be reassigned, and it can't be redeclared.

For example:

const MY_CONST = 10; 
// This will throw an error because we have reassigned again. 
MY_CONST = 20; 
 
// will print 10 
console.log("my favorite number is: " + MY_CONST); 
 
// const also works on objects 
const MY_OBJECT = {"key": "value"};  

Here is our final router config:

ReactDOM.render(( 
    <Router history={browserHistory}> 
    <Route path="/" component={PageLayout}> 
    <IndexRoute component={TwoColumnLayout}/> 
    <Route path="/profile" component={Profile} /> 
    <Route path="/alltickets" component={allTickets} /> 
    <Route path="/newticket" component={AddTicketsForm} /> 
    </Route> 
    <Route path="*" component={NoMatch}/> 
    </Router> 
), document.getElementById('root')); 

Bootstrap table

Let's look at the following key points:

  • Striped rows: Use .table-striped in <table class="table table-striped"> for zebra stripping in table rows
  • Bordered table: Add .table-bordered to add borders in whole and cells
  • Hover rows: Add .table-hover to enable a hover state on table rows
  • Condensed table: Add .table-condensed to reduce the cell padding
  • Contextual classes: Use contextual classes (.active, .success, .info, .warning, .danger) to add a background color to table rows or cells

Apply these classes on the table and see how they make an impact on table's look and feel.

Bootstrap responsive tables

When creating responsive tables, we need to wrap any .table in .table-responsive to make them scroll horizontally on small devices (under 768 px). When we are viewing them on anything larger than 768 px wide, you will not see any difference in these tables.

Let's submit the ticket again and take a quick look at the table.

Go to the helpdesk drop-down in the navigation and click on view tickets.

Bootstrap responsive tables

You will get the appropriate message (You have not raised any ticket yet.) in the UI if you have not raised any ticket yet.

OK, so let's submit the fresh ticket and open this page again. Once the ticket is added, it will be displayed in your table:

Bootstrap responsive tables

We can see the ticket that we have submitted in the table now.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset