Angular2 - 单选按钮绑定

133

我想在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

当页面加载时,第一个单选按钮未被选中,并且修改未绑定到模型

有什么想法吗?


1
无需样式的动态列表示例可在此处查看:http://www.freakyjolly.com/how-to-show-radio-input-listing-in-angular-6/。 - Code Spy
17个回答

121

使用 [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)]”。


9
ng-control 属性的目的是什么?好像没有它也能正常工作。 - Monsignor
4
在 Angular 4+ 中,必须使用 [(ngModel)] 替代 [(ng-model)]请再次阅读 - Claudio Holanda
1
这仅适用于添加新模式。不适用于编辑模式。我找不到原因。在刚打开时分配模型的值有效,但在从服务器检索值并显示在屏幕上时无效。但如果我将其显示在标签中,则值会显示,但未被选中。 - Vinoth Kumar
5
在我的情况下,我最终使用了value="1" [(ngModel)]="model.options"。将value用方括号括起来并不起作用。 - Sylvan D Ash
2
很奇怪,但在我的情况下,我不得不使用value="1"而非[value]="1"。我正在使用Angular 6。 - codingbbq
@noobcode 我猜你想要与数字1进行比较,而不是字符串"1"。使用value="1"会给你字符串,而[value]="1"则是数字。 - perry

66

注意 - 单选按钮绑定现在是RC4及以上版本的支持特性 - 参见这个答案

单选按钮示例,使用自定义的RadioControlValueAccessor,类似于CheckboxControlValueAccessor(已更新为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"
        };
    }
}

模板.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


4
与提问一样,回答也应该在回答中包含相关代码。虽然这样理论上可以回答问题,但最好在此处包含答案的必要部分以供将来的用户参考,并提供链接以供参考。以链接为主的回答可能会因为链接失效而变得无用。 - Mogsdad
很好..奇怪的是它没有包含在框架中。 - Mourad Zouabi
2
@GregWoods 更新了帖子,并感谢你的拉取请求。 - Nidin Vinayakan
你好,能否请您更新上面的代码以适用于Angular2 RC1?我在导入语句import {CONST_EXPR} from 'angular2/src/facade/lang';中遇到了错误Cannot find module 'angular2/src/facade/lang'。谢谢。 - Naveed Ahmed
1
现在已经原生支持,使用 Angular RC4 及以上版本。 - Ckln
显示剩余4条评论

47

我的手动解决方案涉及在选择新的单选按钮时手动更新 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>

2
@PardeepJain,“get”是TypeScript访问器特性。为复选框发布一个问题。 - Mark Rajcok
@PardeepJain,我不明白你的问题。你想把 {{debug(abc)}} 放在哪里?而且 abc 是什么? - Mark Rajcok
我正在做与@Mark相同的事情,但是{{debug2('abc')}}abc在方法debug2(string){....here abc is not accepted}中不被接受,我不知道为什么?这是我的演示plunkr:http://plnkr.co/edit/SxNyNBGVUJgAfXUKvzrz?p=preview - Pardeep Jain
1
@PardeepJain,“{{}}”绑定在每个变更检测周期中都会重新评估。我在Plunker的AppComponent中实现了ngDoCheck()来计算变更检测周期。从中我们可以看到变更检测被调用了3次。在开发模式下,绑定会被检查两次,因此是6次。 - Mark Rajcok
显示剩余6条评论

37

以下是在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:如何从枚举创建单选按钮并添加双向绑定? 它可以在至少 Angular 2 RC5 上运行。


2
这仅适用于添加新模式。不适用于编辑模式。我找不到原因。在新打开的分配值模型中工作,但在从服务器检索值并显示在屏幕上时不起作用。但是,如果我在标签中显示值,则可以显示,但无法正常工作。 - Vinoth Kumar
1
@VinothKumar,你能让编辑模式工作吗?我遇到了相同的问题。 - Dave Nottage

19

此问题已在 Angular 2.0.0-rc.4 中解决,具体在表单中。

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

然后在主文件中扩展您的启动项。相关部分:

...
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版本的正确答案,另外需要补充的是,枚举类型可以与单选框一起使用。 - Ron
8
运行 RC7 时,我需要在[value]周围加上括号。 - Brian Vander Plaats
1
我认为你需要使用括号,因为你正在使用组件的变量而不是字符串,在我的情况下@Zolcsi的答案很好用! - Naeem Baghi
1
这部分代码中的 disableDeprecatedFormsprovideForms 看起来很神奇,但并没有任何意义。这是冗余的、难以阅读的代码,可能会产生不可预测的结果,规模也无从得知。 - Gherman

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 将当前元素传递给该方法。

4
以下内容解决了我的问题,请考虑在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>

4

目前似乎还不支持单选框输入。应该有一种单选框输入值访问器(类似于复选框的这个,其中设置了“checked”属性在这里),但我没有发现任何东西。所以我自己实现了一个,你可以在这里查看。


4
他们在beta6中加入了这个功能:https://github.com/angular/angular/blob/master/CHANGELOG.md#200-beta6-2016-02-11https://github.com/angular/angular/commit/e725542 https://github.com/angular/angular/commit/8f47aa3 - JimB
@JimB:不幸的是,原生语义似乎与此处不同。 - Kiara Grouwstra

4
[value]="item" 在 Angular 2 和 4 中也可用于 Reactive Forms。
<label *ngFor="let item of items">
    <input type="radio" formControlName="options" [value]="item">
    {{item}}
</label>`

1
如何进行单选? - Belter

3
这是我使用的解决方案。它涉及到单选按钮绑定,但不是绑定到业务数据,而是绑定到单选按钮的状态。这可能不是新项目的最佳解决方案,但对于我的项目是合适的。我的项目有大量使用不同技术编写的现有代码,我正在将其移植到Angular中。旧代码遵循一种模式,即代码非常关心检查每个单选按钮是否为所选。该解决方案是单击处理程序解决方案的变体,其中一些已经在Stack Overflow上提到过。
该解决方案的附加值可能是:
  1. 适用于我必须处理的旧代码模式。
  2. 我创建了一个帮助类,试图减少单击处理程序中的“if”语句数量,并处理任何一组单选按钮。
此解决方案涉及以下内容:
  1. 为每个单选按钮使用不同的模型。
  2. 使用单选按钮的模型设置“checked”属性。
  3. 将单击的单选按钮的模型传递给帮助类。
  4. 帮助类确保模型是最新的。
  5. 在“提交时间”,这允许旧代码检查单选按钮的状态以查看哪个单选按钮通过检查模型被选中。
示例:
<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");
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接