【问题标题】:How to create a Dynamic html form in reactjs using json data?如何使用 json 数据在 reactjs 中创建动态 html 表单?
【发布时间】:2017-07-12 06:29:19
【问题描述】:

您好,任何人都可以帮助我如何使用本地 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 中做到这一点?

【问题讨论】:

  • 您需要检索 JSON 的代码还是只需要呈现 JSON 的代码?
  • 不确定你的意思,你只是想在表单中使用 JSON 数据作为变量吗?像 JSON 是表单组件的属性一样吗?
  • @paqash 我想使用 json 数据将静态 html 控件替换为动态表单。我想知道该怎么做

标签: html forms reactjs dynamic


【解决方案1】:

如果您使用 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】:

    我们要归档一个 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...]
    

    [Here in Data file If i Put "type":"text" 那么它只会考虑 type text 相关的 Props 并且会忽略其他 Porps,比如 src、width 等等...]

    【讨论】:

      【解决方案3】:

      获得 JSON 数据后,您可以通过 map 对其进行动态创建布局,如下所示:

      // 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>

      【讨论】:

      • 我们如何将 json 导入到 react 组件中?假设我的 json 在数据文件夹 app/data/samplejson.json 中,这将如何导入?
      • var data = require(app/data/samplejson');。更多细节在这里:stackoverflow.com/questions/37649695/…
      • @knbibin 我添加了一个工作代码示例,您可以使用它。您可以随意从任何地方导入/获取JSON 数据。
      • 感谢您提供详细示例 :-) 工作正常 :-)
      • 你能帮我解答上一个问题吗?
      猜你喜欢
      • 2017-07-27
      • 2016-04-09
      • 2018-03-14
      • 2019-07-20
      • 2017-07-21
      • 2019-01-06
      • 2019-03-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多