Reputation: 913
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
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
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
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
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