0

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
};

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

5 Comments

thanks for the help. The render component doesn' seem to work. I don't believe I'm implementing it correctly. Could you be more explicit?
You should replace your hardcoded <SingleInput> components with {inputs}, where inputs you populate as shown in my snippet.
OK. That renders, but there's no data. pName doesn't mean anything.
Check in debugger that this.state.data contains actual properties. Alternatively you can try any other way to iterate over properties of object in javascript: stackoverflow.com/questions/8312459/…
Thanks. So you're correct, this.state.data. In my post renderCareerPositions(props) created individual inputs with the right data. How do you do this for this.state.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.