jsldnppl
jsldnppl

Reputation: 913

React form props to state

I've got a Form component that gets passed props via its parent. I would like the form to display these props as default values in their input. I would like to allow the form to be edited and on 'save' to save these new values.

I have played around with a few different solutions that I've found online - although none of them seem to allow the behaviour mentioned above.

Form Component - Form.js

import React, { Component } from 'react';

class ViewBooking extends Component {
  constructor(props) {
    super(props);

    this.state = {
      pitch: this.props.booking.pitch,
      email: this.props.booking.email,
      firstName: this.props.booking.firstName,
      arrivalDate: this.props.booking.arrivalDate,
    }

    this._handleInputChange = this._handleInputChange.bind(this); 
    this._handleUpdateClose = this._handleUpdateClose.bind(this);
    this._handleUpdateBooking = this._handleUpdateBooking.bind(this);
    this._handleDelete = this._handleDelete.bind(this);
  }

  componentWillReceiveProps(nextProps) {
    this.state = {
      pitch: this.nextProps.booking.pitch,
      email: this.nextProps.booking.email,
      firstName: this.nextProps.booking.firstName,
      arrivalDate: this.nextProps.booking.arrivalDate,
    }
  }

  _handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
    var partialState = {};
    partialState[name] = value;
    this.setState(partialState);
  }

  _handleUpdateClose(e) {
    this.props.updateClose();
    e.preventDefault();
  }

  _handleUpdateBooking (e) {
    var tempBooking = {
      pitch: this.state.pitch,
      email: this.state.email,
      firstName: this.state.firstName,
      arrivalDate: this.state.arrivalDate,
    }
    this.props.updateBooking(tempBooking);
    e.preventDefault();
  }

  _handleDelete (e) {
    this.props.deleteBooking();
    e.preventDefault();
  }

  render() { 

    if (this.props.viewFormVisibility === true) {
      var viewFormState = {"display": "block"};  
    } else {
      var viewFormState = {"display": "none"};
    }

    return (
      <div>
        <form style={viewFormState}>
          <h4>View Booking</h4>
          <div className="form-group row">
            <label className="col-2 col-form-label">Pitch</label>
            <div className="col-10">
              <input value={this.props.booking.pitch} onChange={this._handleInputChange} className="form-control" name="pitch" ref="inputPitch" type="number" id="example-number-input"/>
            </div>
          </div>
          <div className="form-group row">
            <label  className="col-2 col-form-label">First Name</label>
            <div className="col-10">
              <input value={this.props.booking.firstName} onChange={this._handleInputChange} className="form-control" ref="firstName" name="firstName" type="text" id="example-text-input"/>
            </div>
          </div>
          <div className="form-group row">
            <label className="col-2 col-form-label">Email</label>
            <div className="col-10">
              <input value={this.props.booking.email} onChange={this._handleInputChange} className="form-control" ref="inputEmail" type="email"  name="email" id="example-email-input"/>
            </div>
          </div>

          <div className="form-group row">
            <label className="col-2 col-form-label">Date</label>
            <div className="col-10">
              <input value={this.props.booking.arrivalDate} onChange={this._handleInputChange} className="form-control" ref="arrivalDate" name="arrivalDate" type="date" id="example-date-input"/>
            </div>
          </div>
          <button type="submit" className="btn btn-primary" onClick={this._handleUpdateBooking}>Save changes</button>
          <button className="btn btn-danger" onClick={this._handleUpdateClose}>Close</button>
          <button onClick={this._handleDelete} className="btn btn-danger">Delete</button>
        </form>
      </div>
    )
  }
}

export default ViewBooking;

Upvotes: 1

Views: 8627

Answers (4)

Sean Bradley
Sean Bradley

Reputation: 3577

Here is a demo of a text input using props from it's parent.

https://codepen.io/seanwasere/pen/KBWNaL?editors=0010

class Form extends React.Component {
  constructor () {
    super()
    this.state = {
      data: ''
    }
    this.handleChange = this.handleChange.bind(this)
  }
  handleChange (e) {
    const newData = e.target.value
    this.setState({
      data: newData
    })
  }
  render () {
    const { data } = this.state
    return (
      <div>
        <form>
          <label>
            Type something:
            <TextInput value={data} handleInputChange={this.handleChange} />
          </label>
          <div>
            You typed : {data}
          </div>
        </form>
        </div>
      )
   }
}

class TextInput extends React.Component {
  render () {
    return (      
        <input
          value={this.props.data}
          onChange={this.props.handleInputChange}
        />      
    )
  }
}

ReactDOM.render(
  <Form />,
  document.getElementById('root')
);

Upvotes: 0

Arnold Gandarillas
Arnold Gandarillas

Reputation: 4322

You can do something like this:

class FormParent extends Component {
  constructor (props) {
    super(props)
    this.state = {
      name: ''
    }
    this.handleInputChange = this.handleInputChange.bind(this)
  }
  handleInputChange (e) {
    const { name, value } = e.target
    this.setState({
      [name]: value
    })
  }
  render () {
    const { name } = this.state
    return <Form name={name} handleInputChange={this.handleInputChange} />
  }
}

If you are passing the input values by props is not necessary to save them in a state, you can set them directly to the input.

Then to change the input values you need to have a method in your parent receiving the new date, in this case handleInputChange.

class Form extends Component {
  render () {
    return (
      <form>
        <input
          name='name'
          value={this.props.name}
          onChange={this.props.handleInputChange}
        />
      </form>
    )
  }
}

Note: The input names should be the same as the keys in your parent state.

Upvotes: 2

Vinay Chaudhary
Vinay Chaudhary

Reputation: 318

There are many mistakes in your code. I have fixed them and below is the working code.

class ViewBooking extends Component {
  constructor(props) {
    super(props)

    this.state = {
      pitch: props.booking.pitch,
      email: props.booking.email,
      firstName: props.booking.firstName,
      arrivalDate: props.booking.arrivalDate
    }

    this._handleInputChange = this._handleInputChange.bind(this)
    this._handleUpdateClose = this._handleUpdateClose.bind(this)
    this._handleUpdateBooking = this._handleUpdateBooking.bind(this)
    this._handleDelete = this._handleDelete.bind(this)
  }

  componentWillReceiveProps(nextProps) {
    this.state = {
      pitch: nextProps.booking.pitch,
      email: nextProps.booking.email,
      firstName: nextProps.booking.firstName,
      arrivalDate: nextProps.booking.arrivalDate
    }
  }

  _handleInputChange(event) {
    const target = event.target
    const value = target.type === 'checkbox' ? target.checked : target.value
    const name = target.name
    var partialState = {}
    partialState[name] = value
    this.setState(partialState)
  }

  _handleUpdateClose(e) {
    this.props.updateClose()
    e.preventDefault()
  }

  _handleUpdateBooking(e) {
    var tempBooking = {
      pitch: this.state.pitch,
      email: this.state.email,
      firstName: this.state.firstName,
      arrivalDate: this.state.arrivalDate
    }
    this.props.updateBooking(tempBooking)
    e.preventDefault()
  }

  _handleDelete(e) {
    this.props.deleteBooking()
    e.preventDefault()
  }

  render() {
    if (this.props.viewFormVisibility === true) {
      var viewFormState = { 'display': 'block' }
    } else {
      var viewFormState = { 'display': 'none' }
    }

    return (
      <div>
        fdsfdsfdf
        <form style={viewFormState}>
          <h4>View Booking</h4>
          <div className='form-group row'>
            <label className='col-2 col-form-label'>Pitch</label>
            <div className='col-10'>
              <input value={this.state.pitch} onChange={this._handleInputChange} className='form-control' name='pitch' ref='inputPitch' type='number' id='example-number-input' />
            </div>
          </div>
          <div className='form-group row'>
            <label className='col-2 col-form-label'>First Name</label>
            <div className='col-10'>
              <input value={this.state.firstName} onChange={this._handleInputChange} className='form-control' ref='firstName' name='firstName' type='text' id='example-text-input' />
            </div>
          </div>
          <div className='form-group row'>
            <label className='col-2 col-form-label'>Email</label>
            <div className='col-10'>
              <input value={this.state.email} onChange={this._handleInputChange} className='form-control' ref='inputEmail' type='email' name='email' id='example-email-input' />
            </div>
          </div>

          <div className='form-group row'>
            <label className='col-2 col-form-label'>Date</label>
            <div className='col-10'>
              <input value={this.state.arrivalDate} onChange={this._handleInputChange} className='form-control' ref='arrivalDate' name='arrivalDate' type='date' id='example-date-input' />
            </div>
          </div>
          <button type='submit' className='btn btn-primary' onClick={this._handleUpdateBooking}>Save changes</button>
          <button className='btn btn-danger' onClick={this._handleUpdateClose}>Close</button>
          <button onClick={this._handleDelete} className='btn btn-danger'>Delete</button>
        </form>
      </div>
    )
  }
}

Upvotes: 0

Sajith Edirisinghe
Sajith Edirisinghe

Reputation: 1727

What you have done in the componentWillReceiveProps() is incorrect. You should not directly modify the state (unless it is the constructor). State updates must always happen through this.setState() method as shown below.

componentWillReceiveProps(nextProps) {
    this.setState({
      pitch: nextProps.booking.pitch,
      email: nextProps.booking.email,
      firstName: nextProps.booking.firstName,
      arrivalDate: nextProps.booking.arrivalDate,
    });
 }

Apart from that, the rest of the code seems correct.

Upvotes: 1

Related Questions