如何使用json数据在reactjs中创建动态html表单?

时间:2017-02-22 09:28:52

标签: html forms reactjs dynamic

您可以帮助我如何使用json数据表单本地在reactjs中创建动态html表单。我有以下json格式,其中包含3个字段的表单详细信息。

{
"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"}
    ]
}

及以下是我需要动态创建的表单的反应组件,截至目前我有3个字段是静态的,需要从上面的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

我是新来的反应,有人可以帮我在reactjs中做到这一点吗?

3 个答案:

答案 0 :(得分:3)

获得JSON数据后,可以map覆盖它并动态创建布局,如下所示:

&#13;
&#13;
// 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'));
&#13;
<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>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

如果您正在使用 Formik 和类组件,请参阅以下说明:

假设我在每个属性上都有以下 json 需要在创建产品表单中创建一个字段:

{
  "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);

负责返回动态表单的子组件是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;

答案 2 :(得分:-2)

我们要提交一个data.json文件,另一个是component.js文件 首先从json文件导入数据,然后使用该数据创建自定义表单

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...]

[在数据文件中,如果我输入“ type”:“ text”,则它将仅考虑与文本相关的道具,并且将忽略其他src,宽度等...]