Reputation: 1437
I am fairly new to React Bootstrap and I have been having an annoying issue with checkboxes in a form I am creating.
They won't stay checked when selected after my state updates. They will if I check them again.
I created a toggling function that appends input from selected check boxes in state and sets the checked prop to true. checked={true}
I have written it two ways, both not working.
handleToggle(e) {
e.preventDefault()
const selectedBox = "cb" + e.target.value
this.setState({ goals: this.state.goals + e.target.value, [selectedBox]: e.target.checked })
}
handleToggle(e) {
e.preventDefault()
const selectedBox = "cb" + e.target.value
this.setState({ goals: this.state.goals + e.target.value, [selectedBox]: true })
}
What has been frusturating is that proper values are updating in the state. I threw a debugger in and can see the current state containing a true value for the selected check boxes and the user input appending to whatever is currently under the goals key.
Any direction appreciated. This has been taking a while to debug. Thanks.
Full component -
import React from 'react';
import { connect } from 'react-redux';
import { Button, form, FormGroup, Checkbox, Radio, option, ControlLabel, FormControl, ProgressBar, Pagination, Form } from 'react-bootstrap';
import DatePicker from "react-bootstrap-date-picker";
import { handleChange } from '../helpers';
class Portfolio extends React.Component {
constructor(props) {
super(props)
var value = new Date().toISOString();
this.state = {
date: value,
experience: 1,
progress: 0,
active: false,
goals: "",
cb1: false,
cb2: false,
cb3: false,
cb4: false,
cb5: false
}
this.handleSelect = this.handleSelect.bind(this)
this.handleToggle = this.handleToggle.bind(this)
}
handleSelect(eventKey) {
if (this.state.active === false) {
this.setState({ experience: eventKey, progress: this.state.progress += 20, active: true })
} else {
this.setState({ experience: eventKey })
}
}
handleToggle(e) {
e.preventDefault()
const selectedBox = "cb" + e.target.value
this.setState({ goals: this.state.goals + e.target.value, [selectedBox]: e.target.checked })
}
render() {
const stats = this.props.user.stats
if (!stats || stats.length === 0) {
return(
<div className="portfolio-form-main">
<div className="portfolio-form-container-title-div">
<h1 className="portfolio-title">Profile Information</h1>
</div>
<div className="portfolio-form-container">
<form className="portfolio-form">
<ProgressBar active now={this.state.progress} />
<FormGroup>
<ControlLabel>Choose Your Goals.</ControlLabel>
<Checkbox checked={this.state.cb1} onChange={this.handleToggle} value="1" >
Lose Some Weight
</Checkbox>
{' '}
<Checkbox checked={this.state.cb2} onChange={this.handleToggle} value="2">
Build Strength and Muscle
</Checkbox>
{' '}
<Checkbox checked={this.state.cb3} onChange={this.handleToggle} value="3">
General Health and Wellness
</Checkbox>
{' '}
<Checkbox checked={this.state.cb4} onChange={this.handleToggle} value="4">
Compete in an Event
</Checkbox>
{' '}
<Checkbox checked={this.state.cb5} onChange={this.handleToggle} value="5">
Rehab an Injury
</Checkbox>
</FormGroup>
<FormGroup>
<ControlLabel>Rate Your Exercise Experience Level.</ControlLabel>
<Pagination
bsSize="medium"
items={10}
activePage={this.state.experience}
onSelect={this.handleSelect}
/>
</FormGroup>
<FormGroup>
<ControlLabel>When is Your Birthday?</ControlLabel>
{' '}
<DatePicker value={this.state.value}/>
</FormGroup>
<ControlLabel>How Tall Are You?</ControlLabel>
{' '}
<Form inline>
<FormGroup>
<FormControl type="number"/>
{' '}
<FormControl componentClass="select" placeholder="select">
<option value="select">Unit</option>
<option value="other">in</option>
<option value="other">cm</option>
</FormControl>
</FormGroup>
</Form>
<ControlLabel>How Much Do You Weigh?</ControlLabel>
{' '}
<Form inline>
<FormGroup>
<FormControl type="number"/>
{' '}
<FormControl componentClass="select" placeholder="select">
<option value="select">Unit</option>
<option value="other">Lbs</option>
<option value="other">Kgs</option>
</FormControl>
</FormGroup>
</Form>
<FormGroup >
<ControlLabel>Tell Us About Yourself.</ControlLabel>
{' '}
<FormControl componentClass="textarea" placeholder="textarea" />
</FormGroup>
<Button bsStyle="primary">
Submit
</Button>
</form>
</div>
</div>
)
}
return(
<div>
<ul>
<li>{stats.birthdate}</li>
<li>{stats.weight} {stats.weight_unit}</li>
<li>{stats.height} {stats.height_unit}</li>
<li>{stats.experience}</li>
<li>{stats.about_me}</li>
</ul>
</div>
)
}
}
export default Portfolio
Upvotes: 0
Views: 8454
Reputation: 1437
This works perfectly for selecting and deselecting checkboxes and setting state, adding and removing checked values.
handleToggle(e) {
e.preventDefault()
const selectedBox = "cb" + e.target.value
if (this.state.goals.includes(e.target.value)) {
const goal = this.state.goals.replace(e.target.value, '')
this.setState({ goals: goal, [selectedBox]: e.target.checked })
} else {
this.setState({ goals: this.state.goals + e.target.value, [selectedBox]: e.target.checked })
}
this.props.requestUser(this.props.match.params.userId);
}
Upvotes: 0
Reputation: 71
Removing e.preventDefault()
from the handleToggle
function in your answer should eliminate the need for a forced page refresh.
When a checkbox is clicked React compares the previous value with the next value to decide whether a change has occurred. If it has then a change event is queued.
It seems that React queries the DOM for the checked value before handleToggle
is called, so the checkbox value is True. Then preventDefault()
executes so the checkbox value in the DOM is now False, but React has set the value as True.
So when using preventDefault()
with checkboxes (and possibly radio buttons) you get inconsistencies between the DOM and React.
Upvotes: 4