bp123
bp123

Reputation: 3417

Access form values - array of data

I'm rendering a form with an array of data from the database. When I submit the form, handleFormSubmit(event), I need to grab all of the input fields. Since I don't know what the input fields are called or how many input fields there will be, how do I access the values?

function CareerPosition(props) {
  return (
    <li>
      <SingleInput
        inputType={'text'}
        title={'Company name'}
        name={'position.company'}
        controlFunc={this.handleInputChange}
        defaultValue={props.companyName}
        placeholder={'Company name'}
        bsSize={null}
      />
    </li>

  )
}

export default class CareerHistoryFormPage extends Component {
  constructor(props) {
    super(props);

    this.state = {
      'position.company': '',
      'position.title': '',
      profileCandidateCollectionId: null,
      errors: {}
    };

    this.handleFormSubmit = this.handleFormSubmit.bind(this);
    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  renderCareerPositions(props) {
    const profileCandidateCollection = this.props.profileCandidate;
    const careerHistoryPositions = profileCandidateCollection && profileCandidateCollection.careerHistoryPositions;

    if(careerHistoryPositions) {
      const careerPositions = careerHistoryPositions.map((position) =>
        <CareerPosition
          key={position.uniqueId}
          companyName={position.company}
          positionTitle={position.title}
          uniqueId={position.uniqueId}
        />
      );
      return (
        <ul>
          {careerPositions}
        </ul>
      )
    }
  }

  handleFormSubmit(event) {
    event.preventDefault();

    console.log("AllFormData:", this.state.value);
  }

  render() {
    return (
      <Row className="show-grid">
        <Col sm={12} md={3}>
          <EditCandidateProfileLinks />
        </Col>
        <Col sm={12} md={9}>
          <div className="paper">
            <form className="careerHistoryForm" onSubmit={this.handleFormSubmit}>
              <section className="form-title">
                <h3 className="text-center">Career History</h3>
              </section>
              <hr />
              <section className="form-content">
                {this.state.errors.databaseError ? <AlertNotification bsStyle="danger" error={this.state.errors.databaseError} /> : '' }

                {this.renderCareerPositions()}

                <SingleInput
                  inputType={'text'}
                  title={'Company name'}
                  name={'position.company'}
                  controlFunc={this.handleInputChange}
                  content={this.state['position.company']}
                  placeholder={'Company name'}
                  bsSize={null}
                  error={this.state.errors['position.company']}
                />

                <SingleInput
                  inputType={'text'}
                  title={'Title'}
                  name={'position.title'}
                  controlFunc={this.handleInputChange}
                  content={this.state['position.title']}
                  placeholder={'Title'}
                  bsSize={null}
                  error={this.state.errors['position.title']}
                />

              </section>
              <hr />
              <section className="form-buttons">
                <input type="submit" className="btn btn-primary" value="Save" />
              </section>
            </form>
          </div>
        </Col>
      </Row>
    );
  }
}

CareerHistoryFormPage.propTypes = {
  profileCandidate: PropTypes.object
};

Upvotes: 0

Views: 55

Answers (1)

Amid
Amid

Reputation: 22322

I think we can make it work using some minor changes.

As you have stated data is located in your state as following:

this.state = {
  'position.company': '',
  'position.title': '',
  /*... There are some "service" accommodating data...*/
  profileCandidateCollectionId: null,
  errors: {}
};

And you have no control over amount of its properties as it is fetched from DB. Lets refactor it a bit and put all dynamic data in its own object inside state, like this:

 this.state = {
  data: {
      'position.company': '',
      'position.title': ''
  }
  /*... There are some "service" accommodating data...*/
  profileCandidateCollectionId: null,
  errors: {}
};

Now in your render method we can safely iterate over all properties of the "data" and render one input per each (without need for hardcoding this):

render()
{
    var inputs = [];
    for(var pName of Object.keys(this.state.data))
    {
         inputs.push(
                <SingleInput
                  inputType={'text'}
                  title={'Title'}
                  name={pName}
                  controlFunc={this.handleInputChange}
                  content={this.state.data[pName]}
                  placeholder={'Title'}
                  bsSize={null}
                  error={this.state.errors[pName]}
                />
          );
    }
}

Note I omit how placeholder should be handled - you can do this in the similar manner.

And handleInputChange will look somewhat similar to:

handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    var data = {...this.state.data, ...{[name]: value}};

    this.setState({
      data: data
    });
}

Now after any change of the input - your state.data will always contain updated data - so there is no need to collect it explicitly.

Upvotes: 1

Related Questions