首页 > 解决方案 > React - 如何生成动态表单

问题描述

我有一种形式,我需要为联系人对象添加动态详细信息。我需要将以下格式的数据发送到 API

有效载荷:

{
  name: "The org name",
  detail: "The org detail",
  attributes: {
    address: {
      lines: [],
      city: "",
      state: "",
      country: "India",
      zip: ""
    },
    contacts: [
      {
        name: "abc",
        phone: "PH"
      },
      { 
        name: "x", 
        phone: "PH" 
      }
    ]
  }
};

一切都完成了,但我不知道如何动态设置联系人表单。下面是我的表单代码

export default class OrganizationForm extends Component {
  state = {
    loading: this.props.match.params.id ? true : false,
    organizationForm: {
      name: "",
      detail: "",
      type: "org",
      attributes: {
        contacts: [{
          name: '',
          phone: ''
        }],
        address: {
          lines: [],
          city: "",
          state: "",
          country: "",
          zip: ""
        }
      }
    },
    errors: {}
  };

  componentDidMount() {
    const { match } = this.props;
    if (match.params.id) {
      OrganizationService.getOrganization(match.params.id)
        .then(response => {
          if (response.status === 200) {
            this.setState({
              organizationForm: { ...response.data },
              loading: false
            });
          }
        })
        .catch(function(error) {
          // catch this error on state and show user regarding error
          console.log(error.response);
        });
    }
  }

  handleChange = change => {
    const newState = {
      organizationForm: {
        ...this.state.organizationForm,
        ...change
      }
    };
    this.setState(newState);
  };

  handleSubmit(e) {
    e.preventDefault();
    var id = currentLoggedInUser().belongs.id;
    var callCategoryApi = () => {};
    const { match } = this.props;
    const data = { ...this.state.organizationForm };
    // make this contacts part of handle change and then remove it.
    data.attributes.contacts = [];
    if (!match.params.id) {
      callCategoryApi = OrganizationService.createOrganizations(data, id);
    } else {
      callCategoryApi = OrganizationService.editOrganizations(
        data,
        match.params.id
      );
    }
    callCategoryApi
      .then(response => {
        if (response.status === 200) {
          this.props.history.goBack();
        }
      })
      .catch(error => {
        console.log(error.response);
      });
  }
  render() {
    const { organizationForm, loading } = this.state;
    const { match } = this.props;
    if (loading) {
      // replace this loading as per design
      return <h3 style={{ marginTop: "30px" }}>Loading...</h3>;
    }
    return (
      <div className="welcome-wrap">
        <br />
        <h3 className="text-center">
          {match.params.id ? "Edit Organization" : "Add Organization"}
        </h3>
        <hr />
        <Col className="create-content-wrap" sm={12}>
          <form className="">
            <FormGroup className="custom-form-group required row">
              <ControlLabel className="custom-form-control-label col-sm-3">
                Name
              </ControlLabel>
              <FormControl
                className="custom-form-control col-sm-9"
                type="text"
                name="name"
                value={organizationForm.name}
                onChange={event => {
                  this.handleChange({ name: event.target.value });
                }}
              />
            </FormGroup>
            <FormGroup className="custom-form-group required row">
              <ControlLabel className="custom-form-control-label col-sm-3">
                Detail
              </ControlLabel>
              <FormControl
                className="custom-form-control col-sm-9"
                type="text"
                name="detail"
                componentClass="textarea"
                value={organizationForm.detail}
                onChange={event => {
                  this.handleChange({ detail: event.target.value });
                }}
              />
            </FormGroup>
            <FormGroup className="custom-form-group row">
              <ControlLabel className="custom-form-control-label col-sm-3">
                Address
              </ControlLabel>
              <FormControl
                className="custom-form-control col-sm-9"
                type="text"
                name="lines"
                componentClass="textarea"
                value={organizationForm.attributes.address.lines.join("\n")}
                onChange={event => {
                  this.handleChange({
                    attributes: {
                      address: {
                        ...organizationForm.attributes.address,
                        lines: event.target.value.split("\n")
                      }
                    }
                  });
                }}
              />
            </FormGroup>
            <FormGroup className="custom-form-group row">
              <ControlLabel className="custom-form-control-label col-sm-3">
                City
              </ControlLabel>
              <FormControl
                className="custom-form-control col-sm-9"
                type="text"
                name="city"
                value={organizationForm.attributes.address.city}
                onChange={event => {
                  this.handleChange({
                    attributes: {
                      address: {
                        ...organizationForm.attributes.address,
                        city: event.target.value
                      }
                    }
                  });
                }}
              />
            </FormGroup>
            <FormGroup className="custom-form-group row">
              <ControlLabel className="custom-form-control-label col-sm-3">
                State
              </ControlLabel>
              <FormControl
                className="custom-form-control col-sm-9"
                type="text"
                name="state"
                value={organizationForm.attributes.address.state}
                onChange={event => {
                  this.handleChange({
                    attributes: {
                      address: {
                        ...organizationForm.attributes.address,
                        state: event.target.value
                      }
                    }
                  });
                }}
              />
            </FormGroup>
            <FormGroup className="custom-form-group row">
              <ControlLabel className="custom-form-control-label col-sm-3">
                Country
              </ControlLabel>
              <FormControl
                className="custom-form-control col-sm-9"
                type="text"
                name="country"
                value={organizationForm.attributes.address.country}
                onChange={event => {
                  this.handleChange({
                    attributes: {
                      address: {
                        ...organizationForm.attributes.address,
                        country: event.target.value
                      }
                    }
                  });
                }}
              />
            </FormGroup>
            <FormGroup className="custom-form-group row">
              <ControlLabel className="custom-form-control-label col-sm-3">
                Zipcode
              </ControlLabel>
              <FormControl
                className="custom-form-control col-sm-9"
                type="number"
                name="zip"
                value={organizationForm.attributes.address.zip}
                onChange={event => {
                  this.handleChange({
                    attributes: {
                      address: {
                        ...organizationForm.attributes.address,
                        zip: event.target.value
                      }
                    }
                  });
                }}
              />
            </FormGroup>
            <FormGroup className="custom-form-group row">
              <ControlLabel className="custom-form-control-label col-sm-3">
                Contacts
              </ControlLabel>
              <FormControl
                className="custom-form-control col-sm-9"
                type="number"
                name="contacts"
                // value={organizationForm.attributes.contacts}
                // onChange={this.handleChange.bind(this)}
              />
            </FormGroup>
          </form>
        </Col>
        <div className="">
          <Link to="/stw/setting/organization" className="btn btn-secondary">
            Cancel
          </Link>
          <button
            type="submit"
            className="btn btn-primary ml-2"
            onClick={event => this.handleSubmit(event)}
          >
            Save
          </button>
        </div>
      </div>
    );
  }
}

应该有一个添加联系人和删除联系人按钮,单击该按钮,我应该从表单中添加或删除联系人。

如何从我的表单创建动态联系人数组?

更新 表单现在如下所示,当我单击添加联系人时,它应该再添加 2 个姓名和电话文本框,并且添加联系人按钮应该位于该 2 个文本框下方。

在此处输入图像描述

标签: reactjs

解决方案


在您的州名为 currentContact 的 store 和附加选项,如下所示:

state= {
   currentContact: {name: '', phone: ''},
   showContactForm: false,
   organizationForm: {...}
}

那么你可以这样做:

<FormGroup className="custom-form-group row">
  <ControlLabel className="custom-form-control-label col-sm-3">
    Contacts
  </ControlLabel>
   <button onClick={this.showContactForm}>add contact</button>
     {this.state.showContactForm && 
      <FormGroup className="custom-form-group row">
       <ControlLabel className="custom-form-control-label col-sm-3">
           name
       </ControlLabel>
     <FormControl
       className="custom-form-control col-sm-9"
       type="text"
       name="name"
       onChange={this.handleNameChange}
     />
       <ControlLabel className="custom-form-control-label col-sm-3">
           phone
       </ControlLabel>
     <FormControl
       className="custom-form-control col-sm-9"
       type="text"
       name="phone"
       onChange={this.handlePhoneChange}
     />

       </FormGroup>
   }
   {this.state.organizationForm.attributes.contacts.map((contact,index)=>{
       return <div>{contact.name}<button onClick={()=>{this.removeContact(index)}}>remove</button></div>
   })}
</FormGroup>

组件中的 removeContact 函数应该是:

removeContact = (index)=>{
     const {contacts} = this.state.organizationForm.attributes;           
     contacts.splice(index,1);
     this.handleChange({attributes: {contacts});
}

addContact 函数:

showContactForm = (e)=>{
     e.preventDefault();
     if(!this.state.showContactForm){
        this.setState({showContactForm: true});
     } else {
         this.addContact(e)
     }
}
addContact = (e)=>{
     e..preventDefault();
     const {name, phone} = this.state.currentContact;
     const {contacts} = this.state.organizationForm.attributes;          
     contacts.push(this.state.currentContact);
     this.handleChange({attributes: {...this.state.organizationForm.attributes, contacts}});
}

handleNameChange 和 handlePhoneChange 函数:

   handleNameChange = (e)=>{
      this.setState({currentContact: {...this.state.currentContact, name: 
      e.target.value}})
   }

   handlePhoneChange = (e)=>{
      this.setState({currentContact: {...this.state.currentContact, phone: 
      e.target.value}})
   }

推荐阅读