1

Hi can anyone help me how to create a dynamic html form in reactjs using the json data form local. I have the below json format which contains the form details for 3 fields.

{
"sampleData":
    [{"indexId":"1",
    "abrvIndexName":"firstname",
    "indexDesc":"First Name",
    "htmlControlType":"textbox",
    "cssClassName":"form-control"},
    {"indexId":"2",
    "abrvIndexName":"lastname",
    "indexDesc":"Last Name",
    "htmlControlType":"textbox",
    "cssClassName":"form-control"}
    {"indexId":"3",
    "abrvIndexName":"address",
    "indexDesc":"Address",
    "htmlControlType":"textarea",
    "cssClassName":"form-control"}
    ]
}

and below is the react component for the form which I need to create dynamically, as of now i have 3 fields which are static and need to dynamically put from the above json.

var React = require('react');
var ReactDOM = require('react-dom');

var Menu = React.createClass({

render: function () {
    return (

        <div className="container">
            <br/>
            <div className="panel panel-primary">
                <div className="panel-heading">Sample Dynamic Form using json data</div>
                    <div className="panel-body">
                            <form className="form-horizontal">
                                <div className="form-group">
                                    <label for="firstname" className="col-sm-2 control-label">First Name</label>
                                        <div className="col-sm-8">
                                            <input type="text" className="form-control" id="firstname" placeholder=""/>
                                        </div>
                                </div>
                                <div className="form-group">
                                    <label for="lastname" className="col-sm-2 control-label">Last Name</label>
                                        <div className="col-sm-8">
                                            <input type="text" className="form-control" id="lastname" placeholder=""/>
                                        </div>
                                </div>
                                <div className="form-group">
                                    <label for="address" className="col-sm-2 control-label">Address</label>
                                        <div className="col-sm-8">
                                            <textarea type="text" className="form-control" id="address" placeholder=""/>
                                        </div>
                                </div>

                                <div className="col-md-10 text-right"> 
                                    <button type="button" className="btn btn-primary">Submit</button>
                                </div>

                            </form>


                    </div>      
            </div>
        </div>
    )
}

});
module.exports = Menu

I'm new to react so,Can anyone help me how to do that in reactjs?

knbibin
  • 1,099
  • 7
  • 18
  • 36
  • Do you need the code that retrieves the JSON or just code that will render the JSON? – paqash Feb 22 '17 at 09:38
  • Not sure what you mean, are you just wanting to use JSON data as variables in the form? Like the JSON is a property of the form component? – Jayce444 Feb 22 '17 at 09:42
  • @paqash I want to replace the static html controls to a dynamic form using the json data. I want to know how to do that – knbibin Feb 22 '17 at 10:05

3 Answers3

3

Once you have the JSON data, you can map over it and create the layout dynamically, something like that:

// You can `require` a local file or `fetch` it from somewhere
// For the demo purpose, I just included it here.
const JSON = [  
    {  
        "indexId":"1",
        "abrvIndexName":"firstname",
        "indexDesc":"First Name",
        "htmlControlType":"textbox",
        "cssClassName":"form-control"
    },
    {  
        "indexId":"2",
        "abrvIndexName":"lastname",
        "indexDesc":"Last Name",
        "htmlControlType":"textbox",
        "cssClassName":"form-control"
    },
    {  
        "indexId":"3",
        "abrvIndexName":"address",
        "indexDesc":"Address",
        "htmlControlType":"textarea",
        "cssClassName":"form-control"
}];

var Menu = React.createClass({

    renderFormGroups: function() {
        // Assume your data is fetched/available
        const data = JSON;

        // Here we build the form's groups elements dynamically
        return data.map(group => {
            return <div className="form-group">

                <label for={group.abrvIndexName}
                       className={"col-sm-2 " + group.cssClassName}>
                    {group.indexDesc}
                </label>

                 <div className="col-sm-8">
                      <input type="text"
                             className="form-control"
                             id={group.abrvIndexName}
                             placeholder="" />
                  </div>

            </div>
        });
    },

    render: function () {
        return (
            <div className="container">
                <div className="panel panel-primary">
                    <div className="panel-heading">Sample Dynamic Form using json data</div>
                    <div className="panel-body">
                        <form className="form-horizontal">
                            {this.renderFormGroups()}
                        </form>
                    </div>      
                </div>
            </div>
        )
    }
});

ReactDOM.render(<Menu />, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>
Jordan Enev
  • 16,904
  • 3
  • 42
  • 67
  • How we can import the json into react component? say my json is in data folder, app/data/samplejson.json, How this will be imported? – knbibin Feb 22 '17 at 10:33
  • `var data = require(app/data/samplejson');`. More details here: http://stackoverflow.com/questions/37649695/how-can-i-parse-through-local-json-file-in-react-js – Jordan Enev Feb 22 '17 at 10:44
  • @knbibin I've added a working code sample, you can play with it. You're free to import/fetch the `JSON` data from everywhere you want. – Jordan Enev Feb 22 '17 at 11:29
  • Thanks for the example in detail :-) working fine :-) – knbibin Feb 22 '17 at 13:14
  • I tried the other way rather than declaring const json, but there we need to add json loaders in webpack config to load the json from local. Getting some errors there.. trying to fix it :) – knbibin Feb 22 '17 at 13:26
  • I have posted another question - http://stackoverflow.com/questions/42642675/creating-dynamic-html-using-json-data-in-reactjs – knbibin Mar 07 '17 at 12:55
  • 1
    Can you help me on the previous question? – knbibin Mar 07 '17 at 12:55
0

If you are using Formik and class component the please see the following sloution:

let say I have following json on every attribute need to create one field in the create product form:

{
  "name": "keychoda",
  "attributes": {
    "General_Attributes": [
      {
        "name": "Product Type",
        "code": "product_code",
        "mandatory": "1",
        "type": "text",
        "max_length": "30",
        "default_value": "cellularphonecase",
        "Hint": "Enter Feed Product Type here",
        "AmazonExportHeader": "feed_product_type",
        "ShopifyExportHeader": "Type",
        "EbayExportHeader": "*Category",
        "GoogleExportHeader": "Google Shopping / Google Product Category"
      },
      {
        "name": "Shop Keeping Unit",
        "code": "shop_keeping_unit",
        "mandatory": "1",
        "type": "text",
        "max_length": "12",
        "default_value": "",
        "Hint": "Enter Product SKU Number",
        "AmazonExportHeader": "item_sku",
        "ShopifyExportHeader": "Variant SKU",
        "EbayExportHeader": "CustomLabel",
        "GoogleExportHeader": ""
      },
      {
        "name": "Brand Name",
        "code": "brand_name",
        "mandatory": "1",
        "type": "dropdown",
        "options": [
          "Oxnoble Group",
          "Membrane"
        ],
        "max_length": "",
        "default_value": "Oxnoble Group",
        "Hint": "Select Brand Name",
        "AmazonExportHeader": "item_sku",
        "ShopifyExportHeader": "Vendor",
        "EbayExportHeader": "*C:Brand",
        "GoogleExportHeader": ""
      },
      {
        "name": "Barcode",
        "code": "barcode",
        "mandatory": "1",
        "type": "number",
        "min_length": "13",
        "max_length": "13",
        "default_value": "",
        "Hint": "Enter EAN / GTIN HERE",
        "AmazonExportHeader": "external_product_id",
        "ShopifyExportHeader": "Variant Barcode",
        "EbayExportHeader": "Product:EAN",
        "GoogleExportHeader": ""
      },
      {
        "name": "Barcode Type",
        "code": "barcode_type",
        "mandatory": "1",
        "type": "dropdown",
        "options": [
          "GTIN",
          "EAN",
          "UPC",
          "ASIN"
        ],
        "min_length": "",
        "max_length": "",
        "default_value": "",
        "Hint": "Select Barcode Type",
        "AmazonExportHeader": "external_product_id_type",
        "ShopifyExportHeader": "",
        "EbayExportHeader": "C:Type",
        "GoogleExportHeader": ""
      },
      {
        "name": "condition_type",
        "code": "condition_type",
        "mandatory": "1",
        "type": "dropdown",
        "options": [
          "New",
          "Used - Acceptable",
          "Used - Good",
          "Used - Like New",
          "Used - Very Good"
        ],
        "min_length": "",
        "max_length": "",
        "default_value": "",
        "Hint": "condition_type",
        "AmazonExportHeader": "condition_type",
        "ShopifyExportHeader": "",
        "EbayExportHeader": "",
        "GoogleExportHeader": ""
      },
      {
        "name": "condition_note",
        "code": "condition_note",
        "mandatory": "1",
        "type": "text",
        "min_length": "",
        "max_length": "",
        "default_value": "",
        "Hint": "condition_note",
        "AmazonExportHeader": "condition_note",
        "ShopifyExportHeader": "",
        "EbayExportHeader": "",
        "GoogleExportHeader": ""
      }
    ],
    "Variation_Attributes": [
      
    ],
    "Dimentions_Attributes": [
      {
        "name": "image1",
        "code": "image1",
        "mandatory": "1",
        "type": "file",
        "default_value": "",
        "Hint": "condition_type",
        "AmazonExportHeader": "condition_type",
        "ShopifyExportHeader": "",
        "EbayExportHeader": "",
        "GoogleExportHeader": ""
      },
            {
        "name": "image2",
        "code": "image2",
        "mandatory": "1",
        "type": "file",
        "default_value": "",
        "Hint": "condition_type",
        "AmazonExportHeader": "condition_type",
        "ShopifyExportHeader": "",
        "EbayExportHeader": "",
        "GoogleExportHeader": ""
      },
      {
        "name": "Short Description",
        "code": "short_description",
        "mandatory": "0",
        "type": "textarea",
        "min_length": "",
        "max_length": "",
        "default_value": "",
        "Hint": "condition_note",
        "AmazonExportHeader": "condition_note",
        "ShopifyExportHeader": "",
        "EbayExportHeader": "",
        "GoogleExportHeader": ""
      }
    ]
  }
}

createproduct.js

import React from 'react';
import { connect } from 'react-redux';
import { axiosInstance }  from "../../network/apis/index";
import { END_POINTS } from "../../utils/Constants";
import { Link } from "react-router-dom";
import DashboardTemplate from '../../components/DashboardTemplate';
import AttributeSet from '../../components/AttributeSet';
import { Formik, Form, Field } from 'formik';
import { ToastContainer, toast } from 'react-toastify';
import { Btn } from '../../components/Controls/Button/Button';


class CreateProduct extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            redirect: false,
            catId: "",
            attributes : {},
            initialvalues: {}
        }
    }

    componentDidMount() {
        const params = new URLSearchParams(window.location.search);
        
        let cat;
        this.props.Categories.some( (item) => {
            return (item._id === params.get('catid')) ? cat = item : "";
        });

        let iniValues = {};
        const obj = Object.values(cat.attributes);
        
        obj.map( entries => {
            
            if(entries.length > 0) {
                entries.map(entry => {
                    let name = "\""+ entry.code + "\"";
                    if(entry.type == "file") {
                        iniValues[name] = null;
                    } else {
                        iniValues[name] = "";
                    }
                    
                })
            }
            
        });

        this.setState(
            {
                catId: cat._id,
                attributes: cat.attributes,
                initialvalues: iniValues
            }
        );
    }

    handleProduct = async (values) => {
        console.log(values);

        let newProductPayload = {
            name: "",
            category_id: "",
            attributes: {}
        }
        
        let combined = [];
        Object.entries(this.state.attributes).map( attributes => {
            combined = combined.concat(...attributes[1]);
        });

        //console.log(combined);
        
        this.buildProductPayload(values, newProductPayload, combined);
        console.log(newProductPayload);

        let url = END_POINTS.createProduct;

        try {
            const response = await axiosInstance.post(url,newProductPayload);
            console.log(response);
            toast.success("Product saved");
            this.setState({redirect: true})
        } catch (error) {
            console.log(error);
            toast.error("Unable to save Product");
        }


    }

    buildProductPayload(values, newProductPayload, combined) {
        Object.entries(values).map((value) => {
            if (value[0] == "name") {
                newProductPayload.name = value[1];
                newProductPayload.category_id = this.state.catId;
            } else {
                for (let i = 0; i < combined.length; i++) {
                    if (combined[i].code == value[0]) {
                        newProductPayload.attributes[value[0]] = { value: value[1], AmazonExportHeader: combined[i].AmazonExportHeader, EbayExportHeader: combined[i].EbayExportHeader, GoogleExportHeader: combined[i].GoogleExportHeader, ShopifyExportHeader: combined[i].ShopifyExportHeader };
                        break;
                    }
                }
            }
        });
    }

    render() {
        console.log(this.state.initialvalues,this.state.attributes);
        return (
            <DashboardTemplate>
                <div className="content_header_bar">
                    <div className="content_header_bar_child content_bar_left">
                        <h3>Create Product</h3>
                    </div>
                    <div className="content_header_bar_child content_bar_right">
                        <Link to="/category-select" className="gray-button">Back</Link>
                    </div>
                </div>

                <div className="create_product_main">

                    <div className="create_product_inner">

                    <ToastContainer />

                        <Formik
                            initialValues={ this.state.initialvalues }
                            onSubmit={(values, { setSubmitting }) => {
                                setTimeout(() => {
                                setSubmitting(false);
                                this.handleProduct(values);
                                }, 500);
                            }}
                        >

                            {({ submitForm, isSubmitting, setFieldValue, values }) => (
                            <Form>

                            <div className="create_product_item">
                                <AttributeSet title="Product Name" fieldname="name" type="text" required="1" />
                            </div>

                                { Object.keys(this.state.attributes).map((attribute,i) => {
                                    
                                    return(
                                        <div key={i} className="create_product_item">
                                            <div className="attribute_set_name">{ attribute.replace("_", " ") }</div>
                                                {this.state.attributes[attribute].length > 0 && this.state.attributes[attribute].map((entry,index) => {
                                                    return(
                                                        <AttributeSet key={index} title={ entry.name } fieldname={entry.code} type={ entry.type } options={entry.options} required={entry.mandatory} sfv={setFieldValue} values={values} />
                                                    )
                                                })}
                                        </div>
                                    )
                                })}

                                <Btn className="create_button create_product_button" handleClick={submitForm} text="Create" />
                            </Form>
                            )}
                        </Formik>
                    </div>
                </div>


            </DashboardTemplate>
        )
    }
}

const mapStateToProps = ({Categories}) => {
    return {
        Categories: Categories
    }
}

export default connect(mapStateToProps,null)(CreateProduct);

and child component which is responsible to return dynamic form is Attributeset.js

import React, {Component} from "react";
import { Field } from 'formik';
import PlaceholderImage from '../../assets/images/image-placeholder.jpg';


class AttributeSet extends Component {
    constructor(props) {
        super(props)
        this.state = {
            file: PlaceholderImage
        }
        this.handleChange = this.handleChange.bind(this)
    }
    handleChange(event) {
        //console.log(this.props.sfv);
        const reader = new FileReader();
        reader.onload = () => {
            if (reader.readyState === 2) {
                this.setState({file: reader.result})
            }
        } 
        reader.readAsDataURL(event.target.files[0]);
        //console.log(this.props.values);
        this.props.sfv(this.props.fieldname, event.currentTarget.files[0]);
        //console.log(this.props.values);
    }
    render() {
        let column = 'four_column';
        var inputValue = '';
        switch (this.props.type) {
            case 'textarea':
                column = 'full_width';
                inputValue =  <Field
                                className="attribute_input"
                                name={this.props.fieldname}
                                type="textarea"
                                rows="4" cols="50"
                                placeholder={
                                    this.props.title
                                }
                                />
                break;
                case 'file':
                    inputValue = <>
                    <img src={
                            this.state.file
                        }
                        alt=""
                        className="image_preview"/>
                <input
                className="attribute_input"
                name={this.props.fieldname}
                type="file"
                onChange={this.handleChange}
                />
                </>
                    break;

                case 'dropdown':
                    inputValue = <Field 
                    as="select" 
                    name={this.props.fieldname}
                    className="attribute_input"
                    >
                        <option value=""></option>
                        { this.props.options && this.props.options.map( (option,i) => {
                            return (
                            <option key={i} value={ option }>{ option }</option>
                            );
                        })}
                    </Field>

                    break;

            default:
                inputValue = <Field
                className="attribute_input"
                name={this.props.fieldname}
                type="text"
                placeholder={
                    this.props.title
                }
                />
                break;
        }

        return (
            <div className={
                `attibute_set ${column}`
            }>
                <div className="attibute_name">
                    {
                    this.props.title
                }</div>
                <div className="attribute_input">

                    {inputValue}

                    <div className="attribute_field_error"></div>
                </div>
            </div>
        );
    }
}

export default AttributeSet;
Hassan Ali Shahzad
  • 2,439
  • 29
  • 32
-2

we have To File One data.json and Other is component.js file first Import The data from json file and then use That data to Create custom form

data.json  


[
   {
      UILabel : "Name",
      type : "text"(put any Type)
      attribute : {
             name : "name",
             minLength : 10,
             MaxLength : 20
             put all The Property Related to input type text
         }
   },

   {
        UILabel : "Gender",
        type : radio,
         attributes: {
                 Put all The attributes Related to gender
                 If you Put Value attribute and if you have type is date,time 
                 and  week then put default value in Proper Formate. or else it will 
                 through an error..
           }
   }
]

import React from 'react';
import fields from './data.json;

const customComponent = () => {
        return (
           fields.map(field => {
                <div className="input-box">
                     <input 
                        type={field.type}
                        name={field.atttibute.name}
                        className={field.attribute.className}
                        max={field.attribute.max
                        maxlength={field.attribute.maxlength}
                        min={field.attribute.min
                        minlength={field.attribute.minlength}
                        src={field.attribute.src}
                        ... Put all The jsx Props ..
                     />
                </div> 
            })
       )
}

[Here in Data file If i Put "type":"text" then it will consider
 only type text Related Props and will Ignore Other Porps like src, width and so on...]

[Here in Data file If i Put "type":"text" then it will consider only type text Related Props and will Ignore Other Porps like src, width and so on...]

The General
  • 1,239
  • 2
  • 17
  • 28