3

Is it possible to create a input checkbox group in react? Where if I have mapped 3 checkboxes and only one can be clicked. Do I just give each one a state and when one is selected then turn the others unchecked?

I've tried radio inputs but I need the ability to have them all unchecked, where as in a radio group once you select one i'm unable to have them all unchecked.

6
  • The best way is use radio for this. Using CSS , just change radio to look like checkbox. Commented Mar 28, 2017 at 4:50
  • @Ved If i have a group of radios and select one then how do i deselect it? Commented Mar 28, 2017 at 4:58
  • Ah.. This is what you can't do with radio. You need checkbox than. Commented Mar 28, 2017 at 5:01
  • @Ved yeah problem with checkbox is you can select more than one. Commented Mar 28, 2017 at 5:26
  • No. You can manage it using multiple statte. But the problem is you need to have multiple states. Commented Mar 28, 2017 at 5:33

4 Answers 4

1

Create a separate component for radio buttons.

DEMO: https://jsfiddle.net/69z2wepo/74970/

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {

    };
    this.childs = [{checked:false},{checked:false},]

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(val,index) {  
  this.childs.forEach((data)=>{
  data.checked = false;
  })
        this.childs[index].checked=val;
    this.setState({})
  }

  render() {
  console.log(this.childs,"this.childs")

    return (
    <div>
       {
        this.childs.map((val,i)=>{
         return  <Child key ={i} index={i} checked={val.checked} handleChange={this.handleInputChange}/> 

        })
       }

    </div>
    );
  }
}

class Child extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
   this.handleChange = this.handleChange.bind(this);
   }
   handleChange(event){
     var value = event.target.value;
         if(this.props.checked=='on'){
      value = false;
     }
     console.log(value);
     this.props.handleChange(value,this.props.index)
   }

    render() {
  return (
  <div>
    <input
            name="test"
            type="radio"
            checked={this.props.checked}
            onChange={this.handleChange} />
            </div>
  )
 }
}


ReactDOM.render(
  <Reservation />,
  document.getElementById('root')
);

CSS:

radios>input[type="radio"] {
    -webkit-appearance: checkbox;
    -moz-appearance: checkbox;
}
Sign up to request clarification or add additional context in comments.

3 Comments

If I have separate component for radio buttons. I create 3 of them and I pass a checked property to one component, how will the others know that they should not be checked?
much appreciated.
fixed the above jsfiddle in the solution below.
0

This type of behavior might be best managed by a library like Redux. With Redux, you could have a reducer that would track the state of each checkbox independently while still having knowledge of the state of the entire checkbox group.

For example, you could have a component with a render() method that derives the checked attribute from your Redux store.

    render() {

        // grab the checked attribute from your Redux store
        // typically, you access the store via props using Provider
        // pass each checkbox an id from the parent, and use this as a key
        // to find its checked value in the store
        let checked = this.props.store[this.props.checkboxId];

        <input id={this.props.checkboxId} className='checkbox' type='checkbox' onChange={this.onChangeHandler} checked={checked} />
        <label className='checkboxLabel' htmlFor={this.props.checkboxId}>{this.props.text}</label>
    }

Your store and reducer would look something like this:

    const initialState = {
         checkbox1: false,
         checkbox2: false,
         checkbox3: false
    };

    const store = (state = initialState, action) => {
        switch (action.type) {
             case ('UPDATE_CHECKBOX'):
                 switch (action.payload.checkboxId) {
                     case 'checkbox1':
                         return Object.assign({}, state, {
                         checkbox1: action.payload.checked
                     });
                     case 'checkbox2':
                         return Object.assign({}, state, {
                         checkbox2: action.payload.checked
                     });
                     case 'checkbox3':
                         return Object.assign({}, state, {
                         checkbox3: action.payload.checked
                     });
                     default:
                         return state;
             default:
                 return state;
    }

Then in your component, the onChangeHandler just dispatches an action that signals the reducer to update the checkbox group state.

    onChangeHandler(event) {

        // grab the id of the checkbox you want to update
        let checkboxToUpdate = event.target.id;

        // set the checked value to be the opposite of what it was
        let checked = !this.props.store[event.target.id];

        // dispatch an action to perform the update
        this.props.dispatch(checkboxActions.updateCheckbox({ checkboxId: checkboxToUpdate, checked }));

     }

The nice thing about this approach is that you can trigger the checked attribute to change in one checkbox if another is clicked. For example, if we change our reducer like so:

    const store = (state = initialState, action) => {
        switch (action.type) {
             case ('UPDATE_CHECKBOX'):
                 switch (action.payload.checkboxId) {
                     case 'checkbox1':
                         return Object.assign({}, state, {
                         checkbox1: action.payload.checked,
                         checkbox2: true,
                         checkbox3: false
                     });
                     case 'checkbox2':
                         return Object.assign({}, state, {
                         checkbox2: action.payload.checked
                     });
                     case 'checkbox3':
                         return Object.assign({}, state, {
                         checkbox3: action.payload.checked
                     });
                     default:
                         return state;
             case 'CLEAR_CHECKBOXES':
                 return Object.assign({}, state, {
                     checkbox1: false,
                     checkbox2: false,
                     checkbox3: false
                  });
             default:
                 return state;
    }

Here we dispatch 'UPDATE_CHECKBOX' when we click on checkbox1, setting checkbox2 to true for its checked attribute and checkbox3 to false. Essentially, we are controlling one checkbox's behavior on click of another! You could also have an action that would set all checkboes' checked attributes to false like CLEAR_CHECKBOXES above. I've left out most of the setup for actions and action-types here, but the Redux docs do a good job of walking you through how to set that up. Hope this helps!

3 Comments

While you could use Redux, I think it's a bit overkill for this scenario. I see the checkbox-group state as a local ui type of state, while Redux is more used for the application state.
Agreed. I think the argument for Redux only comes into play if the component needs to respond to changes in state that cannot be passed down from the parent. For example, if a user logs in and should have default preferences set in the checkbox group, but the checkbox group isn't a child of the login component(s), Redux is a great way to manage this.
nice, but i'm trying to do this without Redux.
0

In addition, If you use material UI then I have a simple solution for you.

        <RadioGroup
          row
          aria-labelledby="demo-row-radio-buttons-group-label"
          name="row-radio-buttons-group"
        >
          <FormControlLabel
            value="female"
            control={<Checkbox />}
            label="Fresh Install"
          />
          <FormControlLabel
            value="male"
            control={<Checkbox />}
            label="Male"
          />
          <FormControlLabel
            value="other"
            control={<Checkbox />}
            label="Other"
          />
        </RadioGroup>

Comments

-1

In a new Jsfiddle, fixed from above. https://jsfiddle.net/SPiara/m3xL2mqm/3/

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      checked: false
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {  
        let checked= this.state.checked;
    this.setState({checked:!checked})
  }

  render() {
    return (
    <div>
      <Child checked={this.state.checked} givenName={'Ram'} handleChange={this.handleInputChange}/>         
      <Child checked={this.state.checked} givenName={'Sham'} handleChange={this.handleInputChange}/>
    </div>
    );
  }
}

class Child extends React.Component {
    render() {
  return (
  <div>
    <label htmlFor={this.props.givenName}>{this.props.givenName}</label>
    <input
      name="test"
      id={this.props.givenName}
      type="radio"
      defaultValue='checked'
      value={this.props.checked}
      onChange={this.props.handleChange} />
    </div>
  )
 }
}

ReactDOM.render(
  <Reservation />,
  document.getElementById('root')
);

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.