0

This is driving me crazy. I have no problem with select drop downs and text fields, but for some reason, I cannot get checkboxes working in a controlled fashion. That it is I want them to 'toggle' and listen to this event in a parent component.

I understand there is a 'checked' property for inputs of type checkbox. Selecting a checkbox gives it a value of 'on'. I take this 'on' value and convert it to true or false, and update the component accordingly.

For some reason, I cannot get this to work, either it is always selected, or it is never selected (if I switch the boolean switch).

export class ControlledCheckbox extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      select: false,
    };
  }

  render() {
    console.info("this.state.select - " + this.state.select);

    let sel = false;

    if (this.state.select !== "on") {
      sel = true;
    } else {
      sel = false;
    }

    return (
      <div>
        <input
          type="checkbox"
          checked={sel}
          onChange={this.handleChangeCheckbox}
        />
      </div>
    );
  }

  handleChangeCheckbox = (e) => {
    console.info("here e.currentTarget.value " + e.currentTarget.value);

    this.setState({
      select: e.currentTarget.value,
    });
    //call passed through callback here
  };
}
1

2 Answers 2

5

value serves a different purpose for checkbox inputs and you should not use it to define your state's value. You need to take a look at the e.currentTarget.checked instead.

export class ControlledCheckbox extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      select: false,
    }
  }

  handleChangeCheckbox = e => {
    this.setState({
      select: e.currentTarget.checked // <--
    })
  }

  render() {
    return (
      <div>
        <input type="checkbox"
          checked={this.state.select}
          onChange={this.handleChangeCheckbox} />
      </div>
    );
  }
}

If you are working with multiple inputs (not only checkboxes) you can follow the approach suggested by react docs, where you can cover multiple input types with only one setState. Keep in mind to define a name in this case, so you can separate your inputs:

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>
        <input type="checkbox"
          name="hasValue"
          checked={this.state.select}
          onChange={this.handleChangeCheckbox} />
      </div>
    );
}

Sign up to request clarification or add additional context in comments.

Comments

2

Your question is about controlled inputs, however your checkbox isn't controlled yet. You rely on the value stored inside checkbox, not inside the state.

this.setState({
   select: e.currentTarget.value, // here
});

Use a value that comes from the state instead.

this.setState((prevState) => ({
   select: !prevState.select,
}));

Note: You can remove the conditions from the render, they are redundant.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.