Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React - How to handle nested forms and its value

Tags:

reactjs

I have to setup one form which have nested values in single form Basically I need to send data in below format to API

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

I used react-bootstrap for handling forms.

below are the currrent code of my form

constructor(props) {
    super(props);
    this.state = this.getInitialState();
  }
  getInitialState() {
    const initialState = {
      organizationForm: {
        name: '',
        detail: '',
        type: 'org',
        attributes: {
          contacts: [{
            name: '',
            phone: ''
          }],
          address: {
            lines: [],
            city: '',
            state: '',
            country: '',
            zip: ''
          }
        }
      },
      errors: {}
    };

    return initialState;
  }

handleChange(e) {
    const organizationForm = this.state.organizationForm;
    var key = e.target.name;
    var value = e.target.value;
    organizationForm[key] = value;
    this.setState({
      organizationForm
    });
  }

Below are the code of form

  <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={this.handleChange.bind(this)}
            />
          </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={this.handleChange.bind(this)}
            />
          </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.lines}
              onChange={this.handleAddressChange.bind(this)}
            />
          </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={this.handleAddressChange.bind(this)}
            />
          </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={this.handleAddressChange.bind(this)}
            />
          </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={this.handleAddressChange.bind(this)}
            />
          </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={this.handleAddressChange.bind(this)}
            />
          </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>

I am noobie in react js world. How can i bind nested fields of address and contacts ?

like image 228
Vishal Avatar asked Sep 07 '18 05:09

Vishal


Video Answer


1 Answers

You can add couple of methods to handle for address and attributes like below Way - 1

<FormControl
      className="custom-form-control col-sm-9"
      type="text"
      name="city"
      value={organizationForm.attributes.address.city}
      onChange={this.handleAddressChange(this)}
 />

handleAddressChange = (e) => {
    const organizationForm = this.state.organizationForm;
    let address = organizationForm.attributes.address;
    var key = e.target.name;
    var value = e.target.value;
    address[key] = value;
    organizationForm.attributes.address = address;
    this.setState({
      organizationForm
    });
  }

This way your form is loosely coupled also . So if any change happens in the child object will not affect the other one. Similarly you can add for all the nested objects like address, attribute etc.

Way - 2

You can do the same by below but you need to handle which object your modifing with in the same method .

<FormControl
          className="custom-form-control col-sm-9"
          type="text"
          name="city"
          value={organizationForm.attributes.address.city}
          onChange={event => { this.handleChange(event, this.state.organizationForm.attributes.address  ,'address'); }}
     />

     <FormControl
          className="custom-form-control col-sm-9"
          type="text"
          name="city"
          value={organizationForm.attributes.address.city}
          onChange={event => { this.handleChange(event, this.state.organizationForm.attributes.contacts  ,'contacts'); }}
     />


     <FormControl
          className="custom-form-control col-sm-9"
          type="text"
          name="city"
          value=onChange={event => { this.handleChange(event, this.state.organizationForm ,'organizationForm'); }}
     />


    handleChange = (e , object , type) => {
        const organizationForm = this.state.organizationForm;
        var key = e.target.name;
        var value = e.target.value;
        object[key] = value;
        if(type === 'address'){
            organizationForm.attributes.address = object;
        } else if (type === 'contacts'){
            organizationForm.attributes.contacts = object;
        } 
        this.setState({
          organizationForm : organizationForm
        });
      }
like image 168
Abdul Avatar answered Nov 15 '22 09:11

Abdul