Angular2 - 单选按钮绑定

Posted

技术标签:

【中文标题】Angular2 - 单选按钮绑定【英文标题】:Angular2 - Radio Button Binding 【发布时间】:2015-10-31 00:04:03 【问题描述】:

我想在使用 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 初始值为 1

当页面加载时,第一个单选按钮没有被选中,修改也没有绑定到模型

有什么想法吗?

【问题讨论】:

此处为电台动态列表示例freakyjolly.com/how-to-show-radio-input-listing-in-angular-6 【参考方案1】:

使用 [value]="1" 而不是 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/>

编辑:

正如 thllbrg 所建议的“对于 angular 2.1+,使用 [(ngModel)] 而不是 [(ng-model)]

【讨论】:

ng-control 属性的作用是什么?看起来没有它一切正常。 在 Angular 4+ 中,您必须使用 [(ngModel)] 而不是 [(ng-model)]再读一遍 这仅适用于添加新模式。不适用于编辑模式。我找不到是什么原因。在新打开的模型分配值中,当我从服务器检索值并显示在屏幕中时,模型工作但不工作。但如果我显示标签值显示但不工作检查。 就我而言,我最终使用了value="1" [(ngModel)]="model.options"。将 value 括在方括号中不起作用 奇怪,但在我的情况下,我也必须使用 value="1" 而不是 [value]="1"。我正在使用 Angular 6【参考方案2】:

注意 - 单选按钮绑定现在是 RC4 及以后的支持的功能 - 请参阅 this answer

使用类似于 CheckboxControlValueAccessor 的自定义 RadioControlValueAccessor 的单选按钮示例(使用 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; 

来源:https://github.com/angular2-school/angular2-radio-button

Plunker 现场演示:http://plnkr.co/edit/aggee6An1iHfwsqGoE3q?p=preview

【讨论】:

就像问题应该在问题中包含相关代码一样,答案也应该包含。这在理论上可以回答这个问题,但最好将答案的基本部分包含在此处以供将来的用户使用,并提供链接以供参考。 Link-dominated answers 可以通过link rot 失效。 太棒了..奇怪的是它没有包含在框架中 很好的解决方案!一个小的补充:我正在使用 css input[type="radio"]:checked 样式,但这仅在使用 _elementRef 的 nativeElement 而不是仅 _elementRef 时对我有效:this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', value == this._elementRef.nativeElement.value); @GregWoods 用新的变化更新了帖子,并感谢拉取请求, 现在原生支持,使用angular rc4及以上【参考方案3】:

我的手动解决方法,包括在选择新单选按钮时手动更新model.options

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' ;

这个Plunker演示了以上内容,以及如何使用按钮来改变选中的单选按钮——即证明数据绑定是双向的:

<button (click)="model.options = 'one'">set one</button>

【讨论】:

我有两个问题。第一:在get debug() 函数中get 代表什么?第二个是:复选框是否有类似这个答案的替代方法?请也提供一些复选框代码。感谢 +1 的精彩回答。 @PardeepJain, get 是TypeScript accessor feature。为复选框发布问题。 can is send parameters in like this ' debug(abc) ' ? @PardeepJain,见plnkr.co/edit/iH3Te9EK7Y1dPXMzfWt6?p=preview。你不能像函数一样调用 setter,所以Anotherdate('2015-05-18T02:30:56') 不起作用。当您尝试为属性分配值时,Setter 会被调用。在我的 plunker 中,我创建了一个 setDate() 函数来\hat 接受一个新的日期值,然后分配给 Anotherdate。该分配将自动调用设置器。 @PardeepJain, 绑定在每个变更检测周期都会重新评估。我在 plunker 的 AppComponent 中实现了ngDoCheck(),以计算更改检测周期。从中我们看到变化检测被调用了 3 次。在开发模式下,绑定是checked twice,因此是 6 次。【参考方案4】:

这是在 Angular2 中使用单选按钮的最佳方式。无需使用 (click) 事件或 RadioControlValueAccessor 来更改绑定的属性值,设置 [checked] 属性即可。

<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/>

我发布了一个使用单选按钮的示例: Angular 2: how to create radio buttons from enum and add two-way binding? 它至少适用于 Angular 2 RC5。

【讨论】:

这仅适用于添加新模式。不适用于编辑模式。我找不到是什么原因。在新打开的模型分配值中,当我从服务器检索值并显示在屏幕中时,模型工作但不工作。但如果我显示标签值显示但不工作检查。 @VinothKumar 你设法让编辑模式工作了吗?我也有同样的问题【参考方案5】:

此问题在 Angular 2.0.0-rc.4 版本中分别以表单形式解决。

在 package.json 中包含 "@angular/forms": "0.2.0"

然后在 main.js 中扩展您的引导程序。相关部分:

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

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

我在 .html 中有这个并且可以完美运行: 值: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>

【讨论】:

这是从 rc4 开始的正确答案,并且补充一下,收音机可以与枚举一起使用。 运行 RC7,我需要在 [value] 周围放置括号 我认为您需要括号,因为您使用组件的变量而不是字符串,在我的情况下,@Zolcsi 的回答很好! 这部分带有disableDeprecatedFormsprovideForms 看起来很神奇,没有任何意义。这些东西有什么作用?这是冗余的不可读代码,导致无法预测的事情规模未知。【参考方案6】:

我一直在寻找处理这些单选按钮的正确方法,这是我在此处找到的解决方案的一个示例:

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

注意将当前元素传递给方法的 onSelectionChange

【讨论】:

【参考方案7】:

似乎还不支持无线电输入。 应该有一个单选输入值访问器(类似于复选框的one,它设置了'checked' attr here)但我没有找到。所以我实现了一个;你可以去看看here。

【讨论】:

他们在 beta6 中添加了它:github.com/angular/angular/blob/master/…github.com/angular/angular/commit/e725542github.com/angular/angular/commit/8f47aa3 @JimB:不幸的是,本地语义似乎是different。【参考方案8】:

[value]="item" 使用 *ngFor 也适用于 Angular 2 和 4 中的响应式表单

<label *ngFor="let item of items">
    <input type="radio" formControlName="options" [value]="item">
    item
</label>`

【讨论】:

单选怎么做??【参考方案9】:

以下解决了我的问题,请考虑在form 标签内添加单选输入并使用[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>

【讨论】:

【参考方案10】:

这是一个适合我的解决方案。它涉及单选按钮绑定——但不是绑定到业务数据,而是绑定到单选按钮的状态。它可能不是新项目的最佳解决方案,但适合我的项目。我的项目有大量使用不同技术编写的现有代码,我将这些代码移植到 Angular。旧代码遵循一种模式,其中代码对检查每个单选按钮非常感兴趣,以查看它是否是选定的。该解决方案是点击处理程序解决方案的一种变体,其中一些已经在 Stack Overflow 上提到过。 该解决方案的附加值可能是:

    适用于我必须使用的旧代码模式。 我创建了一个帮助类来尝试减少“if”语句的数量 在点击处理程序中,并处理任何一组单选按钮。

这个解决方案涉及

    为每个单选按钮使用不同的模型。 使用单选按钮的模型设置“checked”属性。 将单击的单选按钮的模型传递给帮助程序类。 帮助类确保模型是最新的。 在“提交时间”,这允许旧代码检查 单选按钮,通过检查模型来查看选择了哪一个。

例子:

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

...

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

...

当用户点击一个单选按钮时,助手类的selectButton方法 被调用。它传递了单击的单选按钮的模型。 助手类将传入模型的布尔“selected”字段设置为true,并将所有其他单选按钮模型的“selected”字段设置为false。

在初始化期间,组件必须构造一个助手类的实例,其中包含组中所有单选按钮模型的列表。在示例中,“radioButtonGroupList”将是帮助程序类的一个实例,其代码为:

 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");
    
  

【讨论】:

【参考方案11】:

Angular 8 Radio 列表示例:

来源Link

JSON 响应

    [
            
                "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 模板

        <div *ngFor="let module of modules_object">
            <div>module.moduleName</div>
            <table >

                <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>

【讨论】:

【参考方案12】:

最简单的解决方案和解决方法:

<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

【讨论】:

在这种情况下,您如何从一开始就将单选按钮设置为默认值? 还会出现用户频繁更改选择的情况,每次检查都会执行一个函数,【参考方案13】:

我创建了一个版本,方法是只在加载的元素上使用一个点击事件,并将选择的值传递给函数“getSelection”并更新模型。

在您的模板中:

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

你的班级:

export class App 

  price:string;

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

  constructor()    

  model = new SomeData(this.price);

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

查看示例:https://plnkr.co/edit/2Muje8yvWZVL9OXqG0pW?p=info

【讨论】:

【参考方案14】:

根据您的用例,这个答案可能不是最好的,但它确实有效。而不是使用单选按钮来选择男性和女性,使用 &lt;select&gt; &lt;/select&gt; 可以完美地保存和编辑。

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

上面应该可以很好地使用带有patchValue 的FormGroup 进行编辑。对于创建,您可以使用[(ngModel)] 而不是formControlName。仍然有效。

与单选按钮 1 相关的管道工作,我选择使用选择按钮。在视觉和用户体验方面,它似乎不是最好的,但从开发人员的角度来看,它要容易得多。

【讨论】:

【参考方案15】:

在单选按钮更改时获取相应按钮的值 用这些线

<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

【讨论】:

【参考方案16】:

这是我使用的一些适用于 Angular 7 的代码

(注意:过去我有时会使用 Anthony Brenelière 的答案提供的信息,对此我很感激。但是,至少对于 Angular 7,这部分:

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

我发现没有必要。)

我这里的解决方案有三个优点:

    与最常用的推荐解决方案一致。所以这对新项目很有好处。 还允许单选按钮代码类似于 Flex/ActionScript 代码。这对个人来说很重要,因为我正在将 Flex 代码翻译成 Angular。与 Flex/ActionScript 代码一样,它允许代码在单选按钮对象上工作以选中或取消选中或确定单选按钮是否被选中。 与您将看到的大多数解决方案不同,它非常基于对象。一个优点是组织性:它将单选按钮的数据绑定字段组合在一起,例如选中、启用、可见以及可能的其他字段。

示例 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">

示例打字稿:

 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");
    
  ;

使用了两个类:

单选按钮组类:

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;
    
  

;

单选按钮类

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);
    
  


【讨论】:

【参考方案17】:

这可能不是正确的解决方案,但这也是一种选择,希望它对某人有所帮助。

到目前为止,我已经使用(单击)方法获取了 radioButtons 的值,如下所示:

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

在 .ts 文件中,我将预定义变量的值设置为 onChange 函数的 getter 值。

但是在搜索之后我发现了我还没有尝试过的好方法,但使用[(ng-model)] 的链接似乎很好,这里是 github here。这也将RadioControlValueAccessor 用于收音机以及复选框。这是此方法的工作#plnkr# here .

【讨论】:

以上是关于Angular2 - 单选按钮绑定的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地将数据绑定到 Angular2 中的单选按钮?

Angular 2:如何从枚举创建单选按钮并添加双向绑定?

Angular2,Ionic2:如何使用 ngModel 对嵌套 *ngfor 中的单选按钮进行 2way 绑定?

Angular2中的共享单选按钮组件

angular2中带有多个单选按钮的多复选框?

Angular 2 单选按钮事件