17

I think its a very silly doubt but I am stuck in this.. I have multiple radio buttons and I want to uncheck all the radio buttons as soon as I click the other radio button. How can I achieve it in react?

var options = [{id:1,nm:"Appointment fixed"},{id:2,nm:"Call later"},{id:3,nm:"Wrong number"},{id:4,nm:"Don't call again"},{id:5,nm:"Call later"}];
{options.map((item,i) => {
                     return (
                        <div onChange={(i)=>this.callOptions(i)}>
                           <label className="radio-inline"><input type="radio" value={i} ref={'ref_' + i} value={item.id}/>{item.nm}</label>
                        </div>
                      )
                  })}
Saif Ali Khan
  • 818
  • 3
  • 9
  • 34
  • Are you saying that clicking a certain button should unselect all buttons or all buttons except the selected button? – Slepz Jun 01 '17 at 21:57
  • Please have a look at my updated answer. I've added details for some other misses you've done. – Chris Jun 01 '17 at 22:17

4 Answers4

12

Give a common name attribute for you radio button. Change

<input type="radio" value={i} ref={'ref_' + i} value={item.id}/>

to

<input type="radio" value={i} name="abc" ref={'ref_' + i} value={item.id}/>

Suresh Prajapati
  • 3,991
  • 5
  • 26
  • 38
11

You can either use a controlled input or an uncontrolled input. Below an example for each of the solutions.

Before I post that though, allow me to add some useful tips & links for you:

  • I've changed the way you use refs because your approach is now deprecated and discouraged. Please see this post. Also, you almost certainly don't need any refs here whatsoever; do consider removing them.

  • You're not using the key prop for the items you're mapping. I've added that too. Please see this post

  • You might also want to read about controlled vs uncontrolled inputs. Here's another relevant post I made a while ago.

  • You have accidentally added two value props for your checkbox.


Solutions

Controlled

Add a state variable which is toggled each time you select a radio button. Something like:

constructor() {
  super();
  this.state = {checkedRadio: null};
}

changeRadio(e) {
  this.setState(checkedRadio: e.target.value);
}

var options = [{id:1,nm:"Appointment fixed"},{id:2,nm:"Call later"},{id:3,nm:"Wrong number"},{id:4,nm:"Don't call again"},{id:5,nm:"Call later"}];

{options.map((item,i) => {
  return (
    <div key={item.id} onChange={(i)=>this.callOptions(i)}>
      <label className="radio-inline"><input type="radio" checked={this.state.checkedRadio == i} ref={(el) => this["myRadioRef" + i] = el} value={item.id} onChange={this.changeRadio} />{item.nm}</label>
    </div>
   );
 })}

Uncontrolled

The other option is to use an uncontrolled input. All you need to do to your existing code is to add a name prop to your inputs. So like:

var options = [{id:1,nm:"Appointment fixed"},{id:2,nm:"Call later"},{id:3,nm:"Wrong number"},{id:4,nm:"Don't call again"},{id:5,nm:"Call later"}];

{options.map((item,i) => {
  return (
    <div key={item.id} onChange={(i)=>this.callOptions(i)}>
      <label className="radio-inline"><input type="radio" name="myRadio" ref={(el) => this["myRadioRef" + i] = el} value={item.id} onChange={this.changeRadio} />{item.nm}</label>
    </div>
   );
 })}
Community
  • 1
  • 1
Chris
  • 57,622
  • 19
  • 111
  • 137
  • I am trying to adapt the "uncontrolled" solution to my simple form with 2 radio buttons. What does the "this.changeRadio" function do? I am not seeing it in your example. Is there a way for me to avoid using "onChange" and only use my form's "onSubmit" to get the current value of selected button? Thanks! – Marianna S. Sep 13 '18 at 17:27
  • 1
    @MariannaS. First of all, I discourage the use of the uncontrolled solution. That being said, you don't need the `this.changeRadio` method because with the uncontrolled solution you are not letting React internally know of any input change; the browser is solely responsible for that. So you don't need an `onChange` listener at all. If you have a form element you can indeed add an `onSubmit` listener to it and take it from there. You may need a `e.preventDefault()` in the callback of the listener to prevent unwanted behavior. Good luck. – Chris Sep 13 '18 at 17:43
  • Thank you @Chris. Yes, that's what I was doing, but it wasn't working for me because I was getting both values (from 2 radio buttons) not just the selected one. Then I found this [article](https://css-tricks.com/react-forms-using-refs/#react-refs-3) where it was suggested to apply "ref" to the
    element, rather than adding one to each radio input. And that worked for me.
    – Marianna S. Sep 13 '18 at 20:07
1

Also, for a stateless component, if you want to deselect a radio item, you can also use checked property:

const renderRadioGroup = data.map((radio, i) => {
    return (
        <span key={i}>
            <input
                className={radio.class}
                id={radio.id}
                type="radio"
                name={radio.value}
                value={radio.value}
                onChange={e => {
                    onChange(e, itemKey);
                }}
                checked={defaultChecked === radio.value}
            />
            <label htmlFor={radio.id}>{radio.label}</label>
        </span>
    );
}

in this case, defaultChecked is passed as a prop and used as a variable within the Class.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
Phil Lucks
  • 2,704
  • 6
  • 31
  • 57
1

I was trying this on react with bootstrap and I faced the same issue. What you can do is check if the radio button was clicked by using e.target.checked and then check it again with the previous state of the checked value set in state.

For Example this is what's in the render method

<input checked={this.state.radioButton} onClick={this.onClickAvailability} className="form-check-input" type="radio" value="Click" />
<label>Click</label>

And in the event handler

onClickAvailability(e){

            if(e.target.checked && !this.state.radioButton){
                this.setState({
                    radioButton:true,
                })
            }else if(e.target.checked && this.state.radioButton){
                this.setState({
                    radioButton:false,
                })

     }

Please remember to set the initial value to false at the componentDidMount or in the constructor

lp_nave
  • 244
  • 3
  • 17