By using the Dynamic Form Creation approach, we are going to create a new form component for the post actions and modal components to display success and error messages. We are going to reuse them in every parent component that needs those modal components. Furthermore, we are going to create all the input fields from the config file dynamically, since we want to make our code reusable. The reusability part is one of the greatest advantages of the Dynamic Form Creation approach.
So, let’s start.
If you want to see all the basic instructions and complete navigation for the .NET Core series, check out the following link: Introduction to the .NET Core series.
For the complete navigation and all the basic instructions of the React series, check out: Introduction to the React series.
For the previous part check out: React Error Handling
The source code is available at GitHub: React series – react-series-part6-end branch
This post is divided into several sections:
- Success and Error Modal Window Components
- Creating Input Configuration
- Creating Input Elements Dynamically
- CreateOwner Component
- Finalizing the CreateOwner View
- Conclusion
Success and Error Modal Window Components
Let’s start by creating the following folder structure in the component
folder:

First, we are going to modify the SuccessModal.js
file:
import React from 'react'; import Aux from '../../../hoc/Auxiliary/Auxiliary'; import { Modal, Button } from 'react-bootstrap'; import '../ModalStyles.css'; const successModal = (props) => { return ( <Aux> <Modal show={props.show} backdrop='static'> <Modal.Header> {props.modalHeaderText} </Modal.Header> <Modal.Body> <p>{props.modalBodyText}</p> </Modal.Body> <Modal.Footer> <Button bsStyle="success" onClick={props.successClick}>{props.okButtonText}</Button> </Modal.Footer> </Modal> </Aux> ) } export default successModal;
This code is pretty straightforward. We use the
react-bootstrap
components for the modal inside the functional component. Through the props
 object, we send different parameters to our modal and one event as well. This event is going to close this modal once we click on the button.Let’s modify the ErrorModal.js
file in the same manner:
import React from 'react'; import { Modal, Button } from 'react-bootstrap'; import Aux from '../../../hoc/Auxiliary/Auxiliary'; import '../ModalStyles.css'; const errorModal = (props) => { return ( <Aux> <Modal show={props.show} backdrop='static'> <Modal.Header> {props.modalHeaderText} </Modal.Header> <Modal.Body> <p>{props.modalBodyText}</p> </Modal.Body> <Modal.Footer> <Button bsStyle="danger" onClick={props.closeModal}>{props.okButtonText}</Button> </Modal.Footer> </Modal> </Aux> ) } export default errorModal;
Finally, we need to modify the
ModalStyles.css
file:.modal-header { margin: 0; line-height: 1.42857143; font-size: 30px; text-align: center; } .modal-body p { text-align: center; margin-top: 10px; } @media (min-width: 768px){ .modal-dialog { width: 500px !important; margin: 20% auto !important; } }
Excellent.
Now we have our modal components which we can use for the Create, Update or any other component. We have deliberately created two modal components, even though they are almost the same because it is much more readable when we use modal components inside the parent components. You can distinguish right away what is the purpose of the modal just by looking at its name.
Creating Input Configuration
Inside the src
folder, we are going to create the Utility
folder and inside it a new file InputConfiguration.js
. In this file, we are going to store all of our configuration settings for the input elements (name, address, dateOfBirth) which we are going to use in the create and update forms.
We have already installed the moment library, in the previous post, but if you haven’t done it, please do it (we need it for the datepicker control) with the following command:
npm install --save moment
Now let’s modify the
InputConfiguration.js
file:import moment from 'moment'; export const returnInputConfiguration = () => { return { name: { element: 'input', type: 'text', value: '', validation: { required: true }, valid: false, touched: false, errorMessage: '', label: 'Name:' }, address: { element: 'input', type: 'text', value: '', validation: { required: true, maxLength: 60 }, valid: false, touched: false, errorMessage: '', label: 'Address:' }, dateOfBirth: { element: 'datePicker', type: 'text', value: moment(), valid: true, touched: false, errorMessage: '', label: 'Date of birth:' } } }
Later on, in our create component, we are going to transform this object into an array of objects and send it to the
Input
component to create all of the input fields we need on the form. That array will consist of the objects (key-value pairs) where the key is going to be the name or the address or the dateOfBirth (properties from the above object) and the value is going to be the complete configuration part of the same object (type, value, element…).
Creating Inputs Elements Dynamically
The first thing we need to do is to install the react-datepicker
library because we are going to use it for the dateOfBirth control.
Let’s execute the command:
npm install [email protected] --save

In the src folder let’s create the UI
folder. Inside it, we are going to create a new folder Input
and inside it the Input.js
and the Input.css
files:

The Input.js
file is going to be a functional component so let’s modify it accordingly:
import React from 'react'; import Aux from '../../hoc/Auxiliary/Auxiliary'; import { FormGroup, Col, FormControl, ControlLabel } from 'react-bootstrap'; import DatePicker from 'react-datepicker'; import 'react-datepicker/dist/react-datepicker.css'; import './Input.css'; const input = (props) => { let inputField = null; let errorMessage = null; if(props.invalid && props.shouldValidate && props.touched){ errorMessage = (<em>{props.errorMessage}</em>); } return ( <Aux> {inputField} </Aux> ) } export default input;
For now, we are just going to import all the resources we need, initialize the input field and the error message and set up the value for that message if the control is invalid and if it should be validated and if it is touched. We don’t want to show the error if the user didn’t place the mouse cursor inside that component at all. Lastly, we are returning that input field (which is null for now) to the parent component.
Below the if
statement and above the return
block, we are going to add the code for populating the inputField
property:
switch (props.elementType) { case 'input': inputField = ( <FormGroup controlId={props.id}> <Col componentClass={ControlLabel} sm={2}> {props.label} </Col> <Col sm={6}> <FormControl type={props.type} value={props.value} onChange={props.changed} onBlur={props.blur} /> </Col> <Col> <em>{errorMessage}</em> </Col> </FormGroup> ) break; case 'datePicker': inputField = ( <FormGroup controlId={props.id}> <Col componentClass={ControlLabel} sm={2}> {props.label} </Col> <Col sm={6}> <DatePicker selected={props.value} dateFormat="MM/DD/YYYY" readOnly onChange={props.changed} className='datePickerControl' showYearDropdown dropdownMode="select"/> </Col> <Col> <em>{errorMessage}</em> </Col> </FormGroup> ) break; default: inputField = null; }
So, we switch through the element type and if it is the input type we create the input field with all the properties and events it needs. We are doing the same thing for the datePicker control. For our forms, those two input types are going to be enough, but if you for any of your projects need more controls, just simply add additional case statement.
One thing left to do is to modify the Input.css
file:
em{ color: red; margin: 5px 0; } .react-datepicker__day-name, .react-datepicker__day, .react-datepicker__time-name { display: inline-block; width: 30px!important; height: 30px; line-height: 30px; text-align: center; margin: 0.166rem; font-size: 14px; } .react-datepicker__month-container select { font-size: 12px!important; } .datePickerControl { display: block; width: 100%; height: 34px; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 4px; } .react-datepicker__input-container { position: relative; display: inline-block; width: 100%; } .react-datepicker-wrapper { display: inline-block; width: 100%; }
In this class, we are overriding some of the
datePicker
native classes and adding one custom class (.datePickerControl
).
That’s it, we can now continue to the CreateOwner
component.
CreateOwner Component
In the containers
folder and then inside the Owner
folder, let’s create a new folder and name it CreateOwner
. Inside create a new file CreateOwner.js
.
Let’s start modifying that file:
import React, { Component } from 'react'; import Input from '../../../UI/Inputs/Input'; import { Form, Well, Button, FormGroup, Col } from 'react-bootstrap'; import { returnInputConfiguration } from '../../../Utility/InputConfiguration'; class CreateOwner extends Component { state = { ownerForm: {}, isFormValid: false } componentWillMount = () =>{ this.setState({ ownerForm: returnInputConfiguration() }); } render() { return ( <Well> </Well> ) } } export default CreateOwner;
In the code above, we import all the necessary
react-bootstrap
components and the returnInputConfiguration
function from the InputConfiguration.js
file. This component is a class component or a stateful component and in the componentWillMount
lifecycle hook, we update our local state with all the form configuration. The compnentWillMount
hook is going to trigger immediately before the component mounts.Let’s add another line of code between the render
and return
blocks:
const formElementsArray = formUtilityActions.convertStateToArrayOfFormObjects({ ...this.state.ownerForm });
In the
convertStateToArrayOfFormObjects
funcition, we want to convert the ownerForm object into an array of objects to send it to the Input
component. So, let’s add that function in a separate file.
Inside the Utility
folder, create a new file FormUtility.js
. Modify that file by adding the function for the object transformation:
export const convertStateToArrayOfFormObjects = (formObject) => { const formElementsArray = []; for (let key in formObject) { formElementsArray.push({ id: key, config: formObject[key] }); } return formElementsArray; }
Now we need to import this function inside
CreateOwner.js
 file:import * as formUtilityActions from '../../../Utility/FormUtility';
We are going to have more actions inside
FormUtility.js
file therefore, we are importing all of those actions in the CreateOwner.js
component.
We have populated the formElementsArray
, so let’s use it to send all the properties towards the Input
component.
Form Elements Configuration Object
Let’s add this code to the Well
tag:
<Form horizontal onSubmit={this.createOwner}> { formElementsArray.map(element => { return <Input key={element.id} elementType={element.config.element} id={element.id} label={element.config.label} type={element.config.type} value={element.config.value} changed={(event) => this.handleChangeEvent(event, element.id)} errorMessage={element.config.errorMessage} invalid={!element.config.valid} shouldValidate={element.config.validation} touched={element.config.touched} blur={(event) => this.handleChangeEvent(event, element.id)} /> }) } <br /> </Form>
In this code, we are looping through all the objects (input configurations) inside the
formElementsArray
and returning the Input
component with all the necessary properties and events it requires. There is a function handleChangeEvent
, and we are going to create this function to enable validation and two-way binding. But more on that a little bit later.
To see the result of our current actions, let’s modify the App.js
file by adding another route to the CreateOwner
component below the OwnerDetails
route. We shouldn’t forget the import statement as well:
import CreateOwner from './Owner/CreateOwner/CreateOwner';
<Route path="/createOwner" component={CreateOwner} />
If we navigate to the CreateOwner page we are going to see this result:

Fantastic.
We have created our controls, but we still can’t do anything with them yet. But as soon as we implement the handleChangeEvent
function, we will be able to modify and validate our inputs.
Finalizing the CreateOwner View
Let’s add the buttons to our component, to finalize the view part.
Inside the Form
tag and below the <br>
tag add this code:
<FormGroup> <Col mdOffset={6} md={1}> <Button type='submit' bsStyle='info' disabled={!this.state.isFormValid}>Create</Button> </Col> <Col md={1}> <Button bsStyle='danger' onClick={this.redirectToOwnerList}>Cancel</Button> </Col> </FormGroup>
We add two buttons, and the Create button is disabled as long as the form is invalid.
Excellent.
Now our form looks like this:

Everything is working as it’s supposed to.
Conclusion
By reading this post, you’ve learned:
- How to use the Bootstrap modal elements to create reusable modal window components
- To use the simple configuration object for form creation and how to transfer it into an array of objects
- How to transfer a configuration array by using a simple JSX code to a Form View
Thank you for reading the article and I hope you found something useful in it.
In the next part of the series, we are going to learn how to validate our input elements. Furthermore, we are going to use the CreateComponent to send a POST request towards our .NET Core Web API server.