hancho
hancho

Reputation: 1437

React Bootstrap CheckBox not toggling 'checked' Prop on Selection

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

Answers (2)

hancho
hancho

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

bn0
bn0

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

Related Questions