I'm trying to pre-populate a form with data from my mongoDB. I think I'm supposed to use componentDidUpdate() to setState the state of the form field, however, the page goes into an infinite loop. Very new to react so this might be an obvious question, I just haven't been able to find a solution.
Path: ContactDetailsComponent.js
export default class ContactDetails extends React.Component {
constructor(props) {
super(props);
this.state = {
'name.first': '',
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentWillReceiveProps(nextProps) {
var profileCandidate = this.props.profileCandidate;
var firstName = profileCandidate && profileCandidate.name && profileCandidate.name.first;
this.setState({
'name.first': firstName,
})
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit} noValidate>
<input
name="name.first"
type="text"
value={this.state['name.first']}
onChange={this.handleInputChange}
className={this.state.errors['name.first'] ? "validate invalid" : "validate" }
/>
</form>
</div>
)
}
}
ContactDetails.propTypes = {
profileCandidate: PropTypes.object,
};
You can slightly modify you following method
componentWillReceiveProps(nextProps) {
var profileCandidate = nextProps.profileCandidate;
var firstName = profileCandidate && profileCandidate.name && profileCandidate.name.first;
this.setState({
'name.first': firstName,
})
}
This will set the updated props to state.
Thanks
Related
I am using localStorage to store the form details. When the component is mounted I am getting the data in the console. How can I show the data in the form and edit it? I've set the edited state but I am not getting how can I achieve this so that the values will be prefilled?
Here's the code :
class MileStoneForm extends Component {
constructor(props){
super(props)
this.state={
deliverable_name:"",
due_date:"",
deliverable_notes:"",
milestone_based_payment:false,
deliverable_name_error:"",
due_date_error:"",
deliverable_notes_error:"",
percent_rate:0,
percent_rate_error:"",
due_date_select:false,
edit:false,
milestonedata:null;
}
}
componentDidMount(){
let milestonedata=JSON.parse(localStorage.getItem('mileStoneData'))
console.log(milestonedata)
if(this.state.edit===true){
this.setState({
milestonedata:milestonedata
},()=>{this.setEditMileStoneData()})
}
}
setEditMileStoneData=()=>{
const {milestonedata}=this.state
let data={
deliverable_name:milestonedata.milestoneName,
deliverable_notes:milestonedata.description,
due_date:milestonedata.dueDate,
milestone_based_payment:milestonedata.isMilestoneBasedPayment,
percent_rate:milestonedata.percentageRate
}
this.setState({...data})
}
handleSubmit=()=>{
const {deliverable_name,deliverable_name_error,deliverable_notes,deliverable_notes_error,
due_date,due_date_error,milestone_based_payment,percent_rate}=this.state
let pass=true
if(pass){
let data={
description: deliverable_notes,
dueDate: due_date,
isDeleted: false,
isMilestoneBasedPayment: milestone_based_payment,
milestoneName: deliverable_name,
percentageRate: percent_rate,
}
console.log(data)
this.props.handleData(data)
localStorage.setItem('mileStoneData',JSON.stringify(data))
this.setState({
deliverable_name:'',
deliverable_name_error:'',
deliverable_notes:'',
deliverable_notes_error:'',
milestone_based_payment:false,
percent_rate:'',
due_date:'',
due_date_error:''
})
}
}
export default MileStoneForm
You should take a look at the "controlled components" section from React docs.
The thought behind it is:
You create a state object for your form.
You add the state for each form field as its value
You add a function to onChange that updates the satate.
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Controlled component is the way to go here. I usually like to do it this way.
handleChange = (e) => {
// This way when we a change is made within the field this function is called and the name from the input will be changed with the new value provided
this.setState({ [e.target.name] : e.target.value })
}
render(){
<TextInput value = { this.state.NAME_THIS_CORRELATING_TO_THE_KEY_IN_STATE } name = "NAME_THIS_CORRELATING_TO_THE_KEY_IN_STATE" onChange = { this.handleChange }
}
We then do this for all of our components
I have below radio button Component
import React from 'react';
import PropTypes from 'prop-types';
export default class RadioButton extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange = (event) => {
this.props.handleChange(event);
}
render() {
return (
<div>
<input type="radio" name="measureValue" value={this.props.value} onChange={this.handleChange} checked={true}/>
<label>{this.props.value}</label>
</div>
);
}
}
Im using this component as
handleRadioSelect = (event) =>{
this.setState({
selectedRadioValue : event.target.value
})
}
<RadioButton value="Fact" handleChange = { this.handleRadioSelect }/>
Now,I got the error as handleChnage is not a function.
to get value of checked, use the event.target.checked instead of event.target.value, so that:
handleRadioSelect = (event) =>{
this.setState({
radioChecked : event.target.checked
})
}
And your error appear because you need to use the arrow function to this.handleCheck (so you can pass in the event props) so that:
onChange={e => this.handleCheck(e)}
In this case, you do not need to bind it anymore and just use normal function for the handleCheck so that:
handleChange(event) {
this.props.handleChange(event);
}
This is how I normally approach it, hope that helps!
handleChange = (event) => {
let target = event.target;
let name = target.name;
let value = target.type === 'checkbox' ? target.checked : target.value;
this.setState({
[name] : value
})
}
Hope this helps
I'm new to Javascript/React. I've adapted the code in https://reactjs.org/docs/forms.html to set up an array of labels with a single handleInputChange handler.
It works, but it's a bit ugly as I've had to set the label names to be "0", "1", etc.. Is there a cleaner way?
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
inputs: Array(10).fill("-"),
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const inputs = this.state.inputs.slice();
const target = event.target;
inputs[parseInt(target.name)] = target.value;
this.setState({inputs: inputs});
}
render() {
var labels = [...Array(10).keys()].map((i) => {
const iAsString = i.toString();
return <div><label>
<input
name={iAsString}
value={this.state.inputs[i]}
onChange={this.handleInputChange} />
</label></div>
;
});
return (
<form>
{labels}
<p>{this.state.inputs.join(' | ')}</p>
</form>
);
}
}
Edited to make the issue clearer.
currently, want to style an input element when the input element is not empty and the user has entered text. Below is the code snippet. Class is applied when !input_active but when condition is set to (!input_active && !inputEmpty) class does not apply to the input element.
constructor(props) {
super(props);
this.input_text_ref = React.createRef();
this.state = {
input_active: true,
};
}
focus = () => {
console.log("focus");
this.setState({
input_active: true
});
};
blur = () => {
console.log("blur");
this.setState({
input_active: false
});
};
handle_text_input_change = (event) => {
this.props.onChange(event);
this.setState({
text_input_value: event.target.value
});
console.log("withinhandle", this.state.text_input_value);
};
render() {
const {
value,
disabled,
...rest
} = this.props;
const {
input_active
} = this.state;
console.log(input_active);
let input_element_classes = [''];
let inputEmpty = value.length == 0;
console.log("inputempty", inputEmpty);
const inputCompiled = value.length > 0;
if (input_active && !inputEmpty) {
input_element_classes.push('blur');
}
return (
<input {...rest}
className={input_element_classes.join(' ')}
type="text"
ref={this.input_text_ref}
onChange={this.handle_text_input_change}
disabled={disabled}
onBlur={this.blur}
//onKeyDown={this.shouldBlur}
onFocus={this.focus}
/>
);
}
Could someone help me with this? Also, based on input element validation (empty, disabled, the user entering text so on) how can I change the style of the input element. From the code, it's understood that I am using an array of classes (input_element_classes) based on validation I pop the class and push some other class. Is there any other easy way to do this. thanks.
It looks a bit overload. If I got you right, you can write it this way:
export class TextInput extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
isActive: props.value.length > 0
};
}
static defaultProps = {
value: "",
disabled: false
};
onFocus = () => {
this.setState({ isActive: true });
};
onBlur = ({ target }) => {
this.setState({ isActive: target.value.length > 0 });
};
render() {
const { disabled, ...rest } = this.props;
const { isActive } = this.state;
return (
<input
{...rest}
className={`text-input ${isActive ? "active" : ""}`}
type="text"
disabled={disabled}
onBlur={this.onBlur}
onFocus={this.onFocus}
/>
);
}
}
You can find the example in the sandbox https://codesandbox.io/s/zl9mmvmp33
I'm using react-bootstrap and I'm trying to validate a form using the validate-state option. I can't figure out how to use getValidationState() to return error when I submit a form which would turn the input field red. Currently when the form loads I get an error message in console ProfileCandidateForm.getValidationState ReferenceError: error is not defined.
If I remove getValidationState() I can submit the form and if it errors the returns the error to an alert box. I would like to change this to the validate-state in bootstrap.
Any help is appreciated. Still wrapping my head around React.
export default class ProfileCandidateForm extends Component {
constructor(props) {
super(props);
var profileCandidate = this.props.profileCandidate;
var firstName = profileCandidate && profileCandidate.name && profileCandidate.name.first;
this.state = {
firstName: firstName || "",
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSubmit(event) {
event.preventDefault();
var profileCandidate = this.state;
insertProfileCandidate.call({profileCandidate}, (error) => {
if (error) {
alert(error.reason);
}
});
}
getValidationState() {
if (error) return 'error';
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<FormGroup
validationState={this.getValidationState()}
>
<FormControl
type="text"
name="firstName"
value={this.state.firstName}
placeholder="First name"
onChange={this.handleChange}
/>
<FormControl.Feedback />
</FormGroup>
<FormGroup >
<Button type="submit">
Save
</Button>
</FormGroup>
</form>
)
}
}
ProfileCandidateForm.propTypes = {
profileCandidate: PropTypes.object.isRequired,
}
You need to reference the value (state) of the text field in the getValidationState() function. Then return null (for no visible validation), 'success' (for green visible validation), or 'error' (for red validation).
Here is one of my getValidationState funcs.
getValidationState() {
var value = this.state.value;
if (value===null || value==='') { return null; }
var valid = this._getValidity(value)
if (valid===true) {
return 'success';
} else {
return 'error';
}
}