Getting the form values on submit

As we've seen, the state and prop will give you the control to alter the value of the component and handle the state for that component.

OK, now let's add some advanced features in our Add Ticket form, which can validate the user input and display the tickets on the UI.

Ref attribute

React provides ref non-DOM attributes to access the component. The ref attribute can be a callback function and it will execute immediately after the component is mounted.

So we will attach the ref attribute in our form element to fetch the values:

var AddTicket = React.createClass({ 
    handleSubmitEvent: function (event) { 
        event.preventDefault(); 
        console.log("Email--"+this.refs.email.value.trim()); 
        console.log("Issue Type--"+this.refs.issueType.value.trim()); 
        console.log("Department--"+this.refs.department.value.trim()); 
        console.log("Comments--"+this.refs.comment.value.trim()); 
    }, 
    render: function() { 
        return ( 
        ); 
    } 
});

Now, we'll add the JSX of form elements inside the return method:

<form onSubmit={this.handleSubmitEvent}>
    <div className="form-group">
        <label htmlFor="email">Email <span style={style}>*</span>
        </label>
        <input type="text" id="email" className="form-control" 
        placeholder="Enter email" required ref="email"/>
    </div>
    <div className="form-group">
        <label htmlFor="issueType">Issue Type <span style={style}>*
        </span></label>
        <select className="form-control" id="issueType" required
        ref="issueType">
            <option value="">-----Select----</option>
            <option value="Access Related Issue">Access Related 
            Issue</option>
            <option value="Email Related Issues">Email Related
            Issues</option>
            <option value="Hardware Request">Hardware Request</option>
            <option value="Health & Safety">Health & Safety</option>
            <option value="Network">Network</option>
            <option value="Intranet">Intranet</option>
            <option value="Other">Other</option>
        </select>
    </div>
    <div className="form-group">
        <label htmlFor="department">Assign Department <span style=
        {style}>*</span></label>
        <select className="form-control" id="department" required
        ref="department">
            <option value="">-----Select----</option>
            <option value="Admin">Admin</option>
            <option value="HR">HR</option>
            <option value="IT">IT</option>
            <option value="Development">Development</option>
        </select>
    </div>
    <div className="form-group">
        <label htmlFor="comments">Comments <span style={style}>*</span>
        </label>(<span id="maxlength">200</span> characters left)
        <textarea className="form-control" rows="3" id="comments" 
        required ref="comment"></textarea>
    </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>

In the preceding code, I have added the ref attribute on our form elements and onSubmit, calling the function name, handleSubmitEvent. Inside this function, we are fetching the values with this.refs.

Now, open your browser and let's see the output of our code:

Ref attribute

We are successfully getting the values for our component. It's very clear how data is flowing in our component. In the console we can see the values of the form when the user clicks the Submit button.

Now, let display this ticket info in our UI.

First, we need to get the value of the form and manage the state of the form:

var AddTicket = React.createClass({ 
    handleSubmitEvent: function (event) { 
        event.preventDefault(); 
 
        var values  = { 
            date: new Date(), 
            email: this.refs.email.value.trim(), 
            issueType: this.refs.issueType.value.trim(), 
            department: this.refs.department.value.trim(), 
            comment: this.refs.comment.value.trim() 
        }; 
        this.props.addTicketList(values); 
    }, 
)};

Now we will create the AddTicketsForm component, which will be responsible for managing and holding the state of addTicketList(values):

var 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; 
        //pass the item.id in array if we are using key attribute. 
        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> 
        ); 
    } 
});

Let's take a look at the preceding code:

  • getInitialState: This initializes the default state for the <List /> component
  • addTicketList: This holds the value and passes into the updateList with the state
  • updateList: This is for updating the list of the tickets to make our UI in sync

Now we need to create the <List items={items} /> component, which iterates the list when we submit the form:

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

Let's get an understanding of the preceding code:

  • getListOfIds: This will iterate through all the keys in the item, and it will return the list that we have mapped with the <ListPanel item={item}/> component
  • .bind(this): The this keyword will be passed as a second argument, which gives the appropriate value when the function is called

In the render method, we are just rendering the list of elements. In addition, we can also add a condition based on the length inside the render method:

<p className={listItemElements.length > 0 ? "":"bg-info"}> 
    {listItemElements.length > 0 ? listItemElements : "You have not
    raised any ticket yet. Fill this form to submit the ticket"} 
</p> 

It will validate the length, and based on the return value TRUE or FALSE, it will display the message or apply the Bootstrap class, .bg-info.

Now we need to create a <ListPanel /> component that displays the list of tickets in the UI:

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

Now, let's combine our code and see the result in the browser:

var style = {color: "#ffaaaa"}; 
var 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-12"> 
            <List items={items} /> 
            <AddTicket addTicketList={this.addTicketList} /> 
            </div> 
            </div> 
            </div> 
        ); 
    }  
}); 

//AddTicketsForm components code ends here

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

// We'll wrap ListPanel component in List

var List = React.createClass({
    getListOfIds: function (items) {
        return Object.keys(items);
    },
    createListElements: function (items) {
        var item;
        return (
            this
            .getListOfIds(items)
            .map(function createListItemElement(itemId) {
                item = items[itemId];
                return (
                    <ListPanel item={item} />
                );//key={item.id}
            }.bind(this))
            .reverse()
        );
    },
    render: function () {
        var items = this.props.items;
        var listItemElements = this.createListElements(items);
        return (
            <p className={listItemElements.length > 0 ? "":"bg-info"}>
            {listItemElements.length > 0 ? listItemElements : "You
            have not raised any ticket yet. Fill this form to submit
            the ticket"}
            </p>
        );
    }
});

In the preceding code, we are iterating the items and passing as a props in <Listpanel/> component:

var AddTicket = React.createClass({
    handleSubmitEvent: function (event) {
        event.preventDefault();
        var values  = {
            date: new Date(),
            email: this.refs.email.value.trim(),
            issueType: this.refs.issueType.value.trim(),
            department: this.refs.department.value.trim(),
            comment: this.refs.comment.value.trim()
        };
        this.props.addTicketList(values);
    },
    render: function() {
    return (

// Form template

ReactDOM.render( 
    <AddTicketsForm />, 
    document.getElementById('form') 
);

Here is the markup of our HTML page:

<link rel="stylesheet" href="css/bootstrap.min.css">
<style type="text/css">
    div.bg-info {
        padding: 15px;
    }
</style>
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-sm-6">
                <h2>Add Ticket</h2>
                <hr/>
            </div>
        </div>
    </div>
    <div id="form">
    </div>
    <script type="text/javascript" src="js/react.js"></script>
    <script type="text/javascript" src="js/react-dom.js"></script>
    <script src="js/browser.min.js"></script>
    <script src="component/advance-form.js" type="text/babel"></script>
</body>

Open your browser and let's see the output of our form before submitting:

Ref attribute

The following screenshot shows how it looks after submitting the form:

Ref attribute

This looks good. Our first fully functional React component is ready.

Note

Never access refs inside any component, and never attach them to a stateless function.

Observe the following screenshot:

Ref attribute

We are getting this warning message because of the key (an optional) attribute of React, which accepts a unique ID. Every time when we submit the form, it will iterate the List component to update the UI. For example:

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() 
    ); 
},

React provides the add-ons module to solve this type of warning and generate the unique ID, but it is only available in npm. In further chapters, we will show how we can work with React npm modules. Here is a list of some popular add-ons:

  • TransitionGroup and CSSTransitionGroup: For dealing with animations and transitions
  • LinkedStateMixin: To make easy interaction with the user's form input data and the component's state
  • cloneWithProps: Changes the props of the component and makes shallow copies
  • createFragment: Used to create a set of externally keyed children
  • Update: A helper function that makes it easy to deal with data in JavaScript
  • PureRenderMixin: A performance booster
  • shallowCompare: A helper function to do shallow comparison for props and state

Bootstrap helper classes

Bootstrap provides some helper classes to give you a better user experience. In the AddTicketsForm form component, we have used the Bootstrap helper classes *-info , which helps you to convey the meaning of your message with color for screen readers. Some of these are *-muted, *-primary, *-success, *-info, *-warning, and *-danger.

To change the color of the text we can use .text*:

<p class="text-info">...</p>

To change the background color we can use .bg*:

<p class="bg-info">...</p>

Caret

To display the caret that will indicate the direction of the dropdown, we can use:

<span class="caret"></span>

Clearfix

By using clearfix on the parent element, we can clear the float of child elements:

<div class="clearfix">... 
    <div class="pull-left"></div> 
    <div class="pull-right"></div> 
</div> 
..................Content has been hidden....................

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