Angular2 - Radio Button Binding
Asked Answered
V

17

134

I want to use radio button in a form using Angular 2

Options : <br/>

1 : <input name="options" ng-control="options" type="radio" value="1"  [(ng-model)]="model.options" ><br/>

2 : <input name="options" ng-control="options" type="radio" value="2" [(ng-model)]="model.options" ><br/>

model.options initial value is 1

when the page is loaded the first radio button isn't checked and the modifications aren't binded to the model

Any Idea ?

Vizor answered 7/8, 2015 at 13:56 Comment(1)
Radio dynamic listing example here freakyjolly.com/how-to-show-radio-input-listing-in-angular-6Photocurrent
L
122

use [value]="1" instead of value="1"

<input name="options" ng-control="options" type="radio" [value]="1"  [(ngModel)]="model.options" ><br/>

<input name="options" ng-control="options" type="radio" [value]="2" [(ngModel)]="model.options" ><br/>

Edit:

As suggested by thllbrg "For angular 2.1+ use [(ngModel)] instead of [(ng-model)] "

Lilybel answered 6/8, 2016 at 11:44 Comment(6)
What is the purpose of the ng-control attribute? Looks like everything works without it.Exuviate
In Angular 4+ you must use [(ngModel)] instead of [(ng-model)]. Read again.Urbanist
This only working on add new mode. Not working for edit mode. I couldn't find what is the reason. In fresh open assigned value for model working but not working when I retrieve values from server and showing in screen .But if I display in label value showing but not working checked.Andrus
In my case, I ended up using value="1" [(ngModel)]="model.options". Enclosing the value in square brackets wasn't workingCorked
Strange, but in my case too, i had to use value="1" instead of [value]="1". I am using Angular 6Happenstance
@noobcode I'm assuming you wanted to bing agains't the number 1 rather than the string "1". Using value="1" would have given you the string and [value]="1" the number.Sciurine
B
66

Note - radio button binding is now a supported feature in RC4 onwards - see this answer

Radio button example using custom RadioControlValueAccessor similar to CheckboxControlValueAccessor (Updated with Angular 2 rc-1)

App.ts

import {Component} from "@angular/core";
import {FORM_DIRECTIVES} from "@angular/common";
import {RadioControlValueAccessor} from "./radio_value_accessor";
import {bootstrap} from '@angular/platform-browser-dynamic';

@Component({
    selector: "my-app",
    templateUrl: "template.html",
    directives: [FORM_DIRECTIVES, RadioControlValueAccessor]
})
export class App {

    model;

    constructor() {
        this.model = {
            sex: "female"
        };
    }
}

template.html

<div>
    <form action="">
        <input type="radio" [(ngModel)]="model.sex"  name="sex" value="male">Male<br>
        <input type="radio" [(ngModel)]="model.sex"  name="sex" value="female">Female
    </form>

    <input type="button" value="select male" (click)="model.sex='male'">
    <input type="button" value="select female" (click)="model.sex='female'">
    <div>Selected Radio: {{model.sex}}</div>
</div>

radio_value_accessor.ts

import {Directive, Renderer, ElementRef, forwardRef} from '@angular/core';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/common';

export const RADIO_VALUE_ACCESSOR: any = {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => RadioControlValueAccessor),
    multi: true
};

@Directive({
   selector:
       'input[type=radio][ngControl],input[type=radio][ngFormControl],input[type=radio][ngModel]',
   host: {'(change)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
   bindings: [RADIO_VALUE_ACCESSOR]
})
export class RadioControlValueAccessor implements ControlValueAccessor {
   onChange = (_) => {};
   onTouched = () => {};

   constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}

   writeValue(value: any): void {
       this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', value == this._elementRef.nativeElement.value);
   }
   registerOnChange(fn: (_: any) => {}): void { this.onChange = fn; }
   registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
}

Source : https://github.com/angular2-school/angular2-radio-button

Plunker live demo : http://plnkr.co/edit/aggee6An1iHfwsqGoE3q?p=preview

Brook answered 8/1, 2016 at 12:45 Comment(9)
In the same way that questions should include relevant code in the question, answers should, too. This may theoretically answer the question, but it would be best to include the essential parts of the answer here for future users, and provide the link for reference. Link-dominated answers can become invalid through link rot.Pericope
great .. it's strange that it's not included in the frameworkVizor
Great solution! One small addition: I am using css input[type="radio"]:checked for the styling, but this only works for me when using the nativeElement of _elementRef instead of only _elementRef: this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', value == this._elementRef.nativeElement.value);Phanerozoic
Broken in angular2 beta1 onwards due to a breaking change on setElementProperty github.com/angular/angular/blob/master/CHANGELOG.mdDavita
@GregWoods Updated the post with new changes and thanks for the pull request,Brook
Hi, can you please update above code for Angular2 RC1 ? I am receiving error Cannot find module 'angular2/src/facade/lang' on line import {CONST_EXPR} from 'angular2/src/facade/lang';Especially
@NaveedAhmed Updated with Angular 2 rc-1Brook
It is now natively supported, using angular rc4 and aboveMagniloquent
I just implemented this. But I am getting an error. Saying that "ORIGINAL EXCEPTION: No provider for RadioControlRegistry! ORIGINAL STACKTRACE:"Uplift
G
47

My manual workaround, which involves manually updating model.options when a new radio button is selected:

template: `
  <label *ngFor="let item of radioItems">
    <input type="radio" name="options" (click)="model.options = item" 
     [checked]="item === model.options">
    {{item}}
  </label>`

class App {
  radioItems = 'one two three'.split(' ');
  model      = { options: 'two' };
}

This Plunker demonstrates the above, as well as how to use a button to change the selected radio button -- i.e., to prove that the data binding is two-way:

<button (click)="model.options = 'one'">set one</button>
Gamy answered 3/12, 2015 at 4:59 Comment(11)
i have two question. first: in get debug() function what does get stands for ? second is: is there any alternate like this answer for the checkboxes ? please provide some code for checkboxes too. thanks +1 for great answer.Bowers
@PardeepJain, get is a TypeScript accessor feature. Post a question for the checkboxes.Gamy
can is send parameters in like this '{{ debug(abc) }}' ?Bowers
@PardeepJain, I don't understand your question. Where do you want to put {{debug(abc)}}? And what is abc?Gamy
abc is just string, i want to convert into number. so wanna send as parameter from HTML side into class and expect get debug method returns string into number.Bowers
@PardeepJain, I'm not sure what a "parameter from HTML" means, but debug() can do whatever you want it to do... or you can create another component method. You can call this new method like this {{debug2('abc')}} from HTML if you define the method like this debug2(myString:string) { ... } in the component.Gamy
exactly same i am doing @Mark but {{debug2('abc')}} and than abc is not accepted in method debug2(string){....here abc is not accepted} i dont know why ? here is my demo plunkr plnkr.co/edit/SxNyNBGVUJgAfXUKvzrz?p=previewBowers
@PardeepJain, see plnkr.co/edit/iH3Te9EK7Y1dPXMzfWt6?p=preview. You can't call a setter like a function, so Anotherdate('2015-05-18T02:30:56') won't work. Setters get called when you try to assign a value to a property. In my plunker I created a setDate() function to\hat accepts a new date value, which then assigns to Anotherdate. That assignment will automatically call the setter.Gamy
thnq so much...but one thing more why the setter and getter function called too many times as console showing (6 times). surely something gets called again and again.Bowers
@PardeepJain, {{}} bindings get re-evaluated every change detection cycle. I implemented ngDoCheck() in the AppComponent in the plunker to counts change detection cycles. From that we see that change detection is called 3 times. In dev mode, bindings are checked twice, hence the 6 times.Gamy
Mark Rajcok... Thanks. It worked well very well in my code.Allies
D
37

Here is the best way to use radio buttons in Angular2. There is no need to use the (click) event or a RadioControlValueAccessor to change the binded property value, setting [checked] property does the trick.

<input name="options" type="radio" [(ngModel)]="model.options" [value]="1"
       [checked]="model.options==1" /><br/>
<input name="options" type="radio"  [(ngModel)]="model.options" [value]="2"
       [checked]="model.options==2" /><br/>

I published an example of using radio buttons: Angular 2: how to create radio buttons from enum and add two-way binding? It works from at least Angular 2 RC5.

Dew answered 9/9, 2016 at 8:33 Comment(2)
This only working on add new mode. Not working for edit mode. I couldn't find what is the reason. In fresh open assigned value for model working but not working when I retrieve values from server and showing in screen .But if I display in label value showing but not working checked.Andrus
@VinothKumar Did you manage to make edit mode work? I'm having the same issueHardening
B
19

This Issue is solved in version Angular 2.0.0-rc.4, respectively in forms.

Include "@angular/forms": "0.2.0" in package.json.

Then extend your bootstrap in main. Relevant part:

...
import { AppComponent } from './app/app.component';
import { disableDeprecatedForms, provideForms } from '@angular/forms';

bootstrap(AppComponent, [
    disableDeprecatedForms(),
    provideForms(),
    appRouterProviders
]);

I have this in .html and works perfectly: value: {{buildTool}}

<form action="">
    <input type="radio" [(ngModel)]="buildTool" name="buildTool" value="gradle">Gradle <br>
    <input type="radio" [(ngModel)]="buildTool" name="buildTool" value="maven">Maven
</form>
Brainard answered 20/7, 2016 at 14:14 Comment(4)
this is the correct answer as of rc4 and just to add, radios can be used with enums.Judicative
running RC7, I needed to place brackets around [value]Incoming
I think you need brackets because u r using a variable of your component instead of a string, in my case @Zolcsi's answer worked fine!Tenter
This part with disableDeprecatedForms and provideForms looks magical and doesn't make any sense. What do these things do? This is redundant unreadable code making unpredictable things of unknown scale.Fusco
H
6

I was looking for the right method to handle those radio buttons here is an example for a solution I found here:

<tr *ngFor="let entry of entries">
    <td>{{ entry.description }}</td>
    <td>
        <input type="radio" name="radiogroup" 
            [value]="entry.id" 
            (change)="onSelectionChange(entry)">
    </td>
</tr>

Notice the onSelectionChange that passes the current element to the method.

Heterogeneous answered 14/2, 2017 at 5:1 Comment(0)
C
4

Radio input doesn't seem to be supported yet. There should be a radio input value accessor (similar to checkbox's one, where it sets 'checked' attr here) but I didn't find any. So I implemented one; you can check it out here.

Chantel answered 9/8, 2015 at 22:12 Comment(2)
they added it in beta6: github.com/angular/angular/blob/master/… github.com/angular/angular/commit/e725542 github.com/angular/angular/commit/8f47aa3Kursk
@JimB: unfortunately it appears the semantics of the native one are different.Condensate
P
4

[value]="item" using *ngFor also works with Reactive Forms in Angular 2 and 4

<label *ngFor="let item of items">
    <input type="radio" formControlName="options" [value]="item">
    {{item}}
</label>`
Plauen answered 23/5, 2017 at 17:54 Comment(1)
How to do single select??Epps
R
4

The following fixed my issue, please consider adding radio input inside the form tag and use the [value] tag to display the value.

<form name="form" (ngSubmit)="">
    <div *ngFor="let item of options">
        <input [(ngModel)]="model.option_id" type="radio" name="options" [value]="item.id"> &nbsp; {{ item.name }}
    </div>
</form>
Raddled answered 23/8, 2018 at 10:12 Comment(0)
S
3

Here is a solution that works for me. It involves radio button binding--but not binding to business data, but instead, binding to the state of the radio button. It is probably NOT the best solution for new projects, but is appropriate for my project. My project has a ton of existing code written in a different technology which I am porting to Angular. The old code follows a pattern in which the code is very interested in examining each radio button to see if it is the selected one. The solution is a variation of the click handler solutions, some of which have already been mentioned on Stack Overflow. The value added of this solution may be:

  1. Works with the pattern of old code that I have to work with.
  2. I created a helper class to try to reduce the number of "if" statements in the click handler, and to handle any group of radio buttons.

This solution involves

  1. Using a different model for each radio button.
  2. Setting the "checked" attribute with the radio button's model.
  3. Passing the model of the clicked radio button to the helper class.
  4. The helper class makes sure the models are up-to-date.
  5. At "submit time" this allows the old code to examine the state of the radio buttons to see which one is selected by examining the models.

Example:

<input type="radio"
    [checked]="maleRadioButtonModel.selected"
    (click)="radioButtonGroupList.selectButton(maleRadioButtonModel)"

...

 <input type="radio"
    [checked]="femaleRadioButtonModel.selected"
    (click)="radioButtonGroupList.selectButton(femaleRadioButtonModel)"

...

When the user clicks a radio button, the selectButton method of the helper class gets invoked. It is passed the model for the radio button that got clicked. The helper class sets the boolean "selected" field of the passed in model to true, and sets the "selected" field of all the other radio button models to false.

During initialization the component must construct an instance of the helper class with a list of all radio button models in the group. In the example, "radioButtonGroupList" would be an instance of the helper class whose code is:

 import {UIButtonControlModel} from "./ui-button-control.model";


 export class UIRadioButtonGroupListModel {

  private readonly buttonList : UIButtonControlModel[];
  private readonly debugName : string;


  constructor(buttonList : UIButtonControlModel[], debugName : string) {

    this.buttonList = buttonList;
    this.debugName = debugName;

    if (this.buttonList == null) {
      throw new Error("null buttonList");
    }

    if (this.buttonList.length < 2) {
      throw new Error("buttonList has less than 2 elements")
    }
  }



  public selectButton(buttonToSelect : UIButtonControlModel) : void {

    let foundButton : boolean = false;
    for(let i = 0; i < this.buttonList.length; i++) {
      let oneButton : UIButtonControlModel = this.buttonList[i];
      if (oneButton === buttonToSelect) {
        oneButton.selected = true;
        foundButton = true;
      } else {
        oneButton.selected = false;
      }

    }

    if (! foundButton) {
      throw new Error("button not found in buttonList");
    }
  }
}
Sikkim answered 21/2, 2018 at 4:41 Comment(0)
P
2

Angular 8 Radio Listing Example:

Source Link

enter image description here

JSON Response

    [
            {
                "moduleId": 1,
                "moduleName": "Employee",
                "subModules":[
                    {
                        "subModuleId": 1,
                        "subModuleName": "Add Employee",
                        "selectedRightType": 1,
                    },{
                        "subModuleId": 2,
                        "subModuleName": "Update Employee",
                        "selectedRightType": 2,
                    },{
                        "subModuleId": 3,
                        "subModuleName": "Delete Employee",
                        "selectedRightType": 3,
                    }
                ]
            },  
            {
                "moduleId": 2,
                "moduleName": "Company",
                "subModules":[
                    {
                        "subModuleId": 4,
                        "subModuleName": "Add Company",
                        "selectedRightType": 1,
                    },{
                        "subModuleId": 5,
                        "subModuleName": "Update Company",
                        "selectedRightType": 2,
                    },{
                        "subModuleId": 6,
                        "subModuleName": "Delete Company",
                        "selectedRightType": 3,
                    }
                ]
            },  
            {
                "moduleId": 3,
                "moduleName": "Tasks",
                "subModules":[
                    {
                        "subModuleId": 7,
                        "subModuleName": "Add Task",
                        "selectedRightType": 1,
                    },{
                        "subModuleId": 8,
                        "subModuleName": "Update Task",
                        "selectedRightType": 2,
                    },{
                        "subModuleId": 9,
                        "subModuleName": "Delete Task",
                        "selectedRightType": 3,
                    }
                ]
            }
    ]

HTML Template

        <div *ngFor="let module of modules_object">
            <div>{{module.moduleName}}</div>
            <table width="100%">

                <thead>
                    <tr>
                        <th>Submodule</th>
                        <th>
                            <input type="radio" name="{{module.moduleName}}_head_radio" [(ngModel)]="module.selHeader" (change)="selAllColumn(module)" [value]="1"> Read Only
                        </th>
                        <th>
                            <input type="radio" name="{{module.moduleName}}_head_radio" [(ngModel)]="module.selHeader" (change)="selAllColumn(module)" [value]="2"> Read Write
                        </th>
                        <th>
                            <input type="radio" name="{{module.moduleName}}_head_radio" [(ngModel)]="module.selHeader" (change)="selAllColumn(module)" [value]="3"> No Access
                        </th>
                    </tr>
                </thead>

                <tbody>
                    <tr *ngFor="let sm of module.subModules">
                        <td>{{sm.subModuleName}}</td>
                        <td>
                            <input type="radio" [checked]="sm.selectedRightType == '1'" [(ngModel)]="sm.selectedRightType" name="{{sm.subModuleId}}_radio" [value]="1"> 
                        </td>
                        <td class="cl-left">
                            <input type="radio" [checked]="sm.selectedRightType == '2'" [(ngModel)]="sm.selectedRightType" name="{{sm.subModuleId}}_radio" [value]="2"> 
                        </td>
                        <td class="cl-left">
                            <input type="radio" [checked]="sm.selectedRightType == '3'" [(ngModel)]="sm.selectedRightType" name="{{sm.subModuleId}}_radio" [value]="3"> 
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
Photocurrent answered 12/10, 2019 at 9:50 Comment(0)
S
1

Simplest solution and workaround:

<input name="toRent" type="radio" (click)="setToRentControl(false)">
<input name="toRent" type="radio" (click)="setToRentControl(true)">

setToRentControl(value){
    this.vm.toRent.updateValue(value);
    alert(value); //true/false
}
Shaven answered 6/1, 2016 at 11:10 Comment(2)
How would you in this case set a radio button to the default value from the beginning?Cricoid
Also there would be situation where user changes choice frequently, everythime there would be a function exectuted for every check,Pebrook
R
1

I've created a version by using just a click event on the elements loaded and passing the value of the selection into the function "getSelection" and updating the model.

In your template:

<ul>
     <li *ngFor="let p of price"><input type="radio" name="price"      (click)="getValue(price.value)" value="{{p}}" #price> {{p}} 
     </li>
</ul>

Your class:

export class App {

  price:string;

  price = ["1000", "2000", "3000"];

  constructor() {   }

  model = new SomeData(this.price);

  getValue(price){
    this.model.price = price;
  }
}

See example: https://plnkr.co/edit/2Muje8yvWZVL9OXqG0pW?p=info

Rasure answered 21/6, 2016 at 4:0 Comment(0)
I
1

As much as this answer might not be the best depending on your use case, it works. Instead of using the Radio button for a Male and Female selection, using the <select> </select> works perfectly, both for saving and editing.

<select formControlName="gender" name="gender" class="">
  <option value="M">Male</option>
  <option value="F">Female</option>
</select>

The above should do just fine, for editing using FormGroup with patchValue. For creating, you could use [(ngModel)] instead of the formControlName. Still works.

The plumbing work involved with the radio button one, I chose to go with the select instead. Visually and UX-wise, it doesn't appear to be the best, but from a developer's standpoint, it's a ton easier.

Irrelevancy answered 25/3, 2018 at 13:18 Comment(0)
N
1

On Radio button change get the value of the respective buttons with these lines

<label class="radio-inline">
<input class="form-check-input" type="radio" [(ngModel)]="dog" name="cat"  checked (change)="onItemChange($event)" value="Dog" />Dog</label>
<label class="radio-inline">
<input class="form-check-input" type="radio" [(ngModel)]="cat" name="cat"   (change)="onItemChange($event)" value="Cat"  />Cat</label>

https://stackblitz.com/edit/angular-jpo2dm?embed=1&file=src/app/app.component.html

Narrowminded answered 5/12, 2019 at 10:24 Comment(0)
S
0

Here is some code I use that works with Angular 7

(Note: In the past I sometimes used info provided by the answer of Anthony Brenelière, which I appreciate. But, at least for Angular 7, this part:

 [checked]="model.options==2"

I found to be unnecessary.)

My solution here has three advantages:

  1. Consistent with the most commonly recommended solutions. So it is good for new projects.
  2. Also allows radio button code to be similar to Flex/ActionScript code. This is personally important because I am translating Flex code to Angular. Like Flex/ActionScript code it allows code to work on a radio button object to check or uncheck or find out if a radio button is checked.
  3. Unlike most solutions you will see, it is very object-based. One advantage is organization: It groups together data binding fields of a radio button, such as selected, enabled, visible, and possibly others.

Example HTML:

       <input type="radio" id="byAllRadioButton"
                 name="findByRadioButtonGroup"
                 [(ngModel)]="findByRadioButtonGroup.dataBindingValue"
                 [value]="byAllRadioButton.MY_DATA_BINDING_VALUE">         

      <input type="radio" id="byNameRadioButton"
                 name="findByRadioButtonGroup" 
                 [(ngModel)]="findByRadioButtonGroup.dataBindingValue"
                 [value]="byNameRadioButton.MY_DATA_BINDING_VALUE">

Example TypeScript:

 findByRadioButtonGroup : UIRadioButtonGroupModel
    = new UIRadioButtonGroupModel("findByRadioButtonGroup",
                                  "byAllRadioButton_value",
                                  (groupValue : any) => this.handleCriteriaRadioButtonChange(groupValue)
                                  );

  byAllRadioButton : UIRadioButtonControlModel
    = new UIRadioButtonControlModel("byAllRadioButton",
    "byAllRadioButton_value",
    this.findByRadioButtonGroup) ;

  byNameRadioButton : UIRadioButtonControlModel
    = new UIRadioButtonControlModel("byNameRadioButton",
    "byNameRadioButton_value",
    this.findByRadioButtonGroup) ;



  private handleCriteriaRadioButtonChange = (groupValue : any) : void => {

    if ( this.byAllRadioButton.selected ) {

      // Do something

    } else if ( this.byNameRadioButton.selected ) {

      // Do something

    } else {
      throw new Error("No expected radio button selected");
    }
  };

Two classes are used:

Radio Button Group Class:

export class UIRadioButtonGroupModel {


  private _dataBindingValue : any;


  constructor(private readonly debugName : string,
              private readonly initialDataBindingValue : any = null,   // Can be null or unspecified
              private readonly notifyOfChangeHandler : Function = null       // Can be null or unspecified
  ) {

    this._dataBindingValue = initialDataBindingValue;
  }


  public get dataBindingValue() : any {

    return this._dataBindingValue;
  }


  public set dataBindingValue(val : any) {

    this._dataBindingValue = val;
    if (this.notifyOfChangeHandler != null) {
      MyAngularUtils.callLater(this.notifyOfChangeHandler, this._dataBindingValue);
    }
  }



  public unselectRadioButton(valueOfOneRadioButton : any) {

    //
    // Warning: This method probably never or almost never should be needed.
    // Setting the selected radio button to unselected probably should be avoided, since
    // the result will be that no radio button will be selected.  That is
    // typically not how radio buttons work.  But we allow it here.
    // Be careful in its use.
    //

    if (valueOfOneRadioButton == this._dataBindingValue) {
      console.warn("Setting radio button group value to null");
      this.dataBindingValue = null;
    }
  }

};

Radio Button Class

export class UIRadioButtonControlModel {


  public enabled : boolean = true;
  public visible : boolean = true;


  constructor(public readonly debugName : string,
              public readonly MY_DATA_BINDING_VALUE : any,
              private readonly group : UIRadioButtonGroupModel,
              ) {

  }


  public get selected() : boolean {

    return (this.group.dataBindingValue == this.MY_DATA_BINDING_VALUE);
  }


  public set selected(doSelectMe : boolean) {

    if (doSelectMe) {
      this.group.dataBindingValue = this.MY_DATA_BINDING_VALUE;
    } else {
      this.group.unselectRadioButton(this.MY_DATA_BINDING_VALUE);
    }
  }

}
Sikkim answered 21/9, 2019 at 6:43 Comment(0)
B
-1

This may be not the correct solution but this one is also option hope it will help someone.

Till now i had getting the value of radioButtons using (click) method like following:

<input type="radio" name="options" #male (click)="onChange(male.value)">Male
<input type="radio" name="options" #female (click)="onChange(female.value)">Female

and in the .ts file i have set the value of predefined variable to getter value of onChange function.

But after searching i found good method i have't tried yet but it seems this one is good using [(ng-model)] link is here to github here. this is using RadioControlValueAccessor for the radio as well as checkbox too. here is the working #plnkr# for this method here .

Bowers answered 27/12, 2015 at 16:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.