AngularJS - 将单选按钮绑定到具有布尔值的模型

206
我有一个问题,就是如何将单选按钮绑定到具有布尔值属性的对象上。 我试图显示从$resource检索到的考试问题。
HTML:
<label data-ng-repeat="choice in question.choices">
  <input type="radio" name="response" data-ng-model="choice.isUserAnswer" value="true" />
  {{choice.text}}
</label>

JS:

$scope.question = {
    questionText: "This is a test question.",
    choices: [{
            id: 1,
            text: "Choice 1",
            isUserAnswer: false
        }, {
            id: 2,
            text: "Choice 2",
            isUserAnswer: true
        }, {
            id: 3,
            text: "Choice 3",
            isUserAnswer: false
        }]
};   

使用这个示例对象,“isUserAnswer:true”属性不会导致单选按钮被选中。如果我将布尔值封装在引号中,则可以正常工作。

JS:

$scope.question = {
    questionText: "This is a test question.",
    choices: [{
            id: 1,
            text: "Choice 1",
            isUserAnswer: "false"
        }, {
            id: 2,
            text: "Choice 2",
            isUserAnswer: "true"
        }, {
            id: 3,
            text: "Choice 3",
            isUserAnswer: "false"
        }]
};   
很遗憾,我的REST服务把那个属性当作布尔类型对待,改变JSON序列化方式来将这些值放在引号中封装起来会很困难。是否有其他方法可以设置模型绑定而不改变模型的结构?
这是jsFiddle,展示了无法工作和能够工作的对象。 Here's the jsFiddle showing non-working and working objects
7个回答

392
在AngularJS中处理非字符串的模型值时,正确的做法是使用ng-value。请按照以下方式修改您的代码:
<label data-ng-repeat="choice in question.choices">
  <input type="radio" name="response" data-ng-model="choice.isUserAnswer" data-ng-value="true" />
  {{choice.text}}
</label>

参考资料:权威消息来源


13
只想添加一个重要的侧面说明: ng-value必须没有花括号{{}}的值。 例如:ng-value="choice2.id"与value="{{choice2.id}}"。 - Andi
3
你是指 data- 前缀吧... data- 前缀的作用是使 HTML 有效(尽管没有它,所有现代浏览器也可以正确处理 HTML)。 - kumarharsh
8
我知道这篇帖子很旧,但我现在遇到了同样的问题。但当我使用你的解决方案并更改单选按钮时,所有曾经被选中的都是真的,它们不会切换回假。有没有解决办法?(该问题也存在于原帖的 Fiddle 中) - Dominik G
请查看Angular文档:https://docs.angularjs.org/api/ng/input/input%5Bradio%5D - Ilker Cat
有人能解释一下为什么我不得不添加ng-checked属性才能让它正常工作吗? <input type="radio" name="hospitality" ng-model="model.hospitality" ng-value="true" ng-checked="model.hospitality===true" ng-required="model.hospitality===null"> (我正在使用Umbraco,所以被迫使用Angular v1.1.4,也许这就是原因) - jenson-button-event
显示剩余6条评论

21

使用 isUserAnswer 的方法有些奇怪。你真的要发送所有三个选项回服务器,并在服务器上循环遍历每个选项以检查 isUserAnswer == true 吗?如果是这样,可以尝试这个:

http://jsfiddle.net/hgxjv/4/

HTML:

<input type="radio" name="response" value="true" ng-click="setChoiceForQuestion(question1, choice)"/>

JavaScript:

$scope.setChoiceForQuestion = function (q, c) {
    angular.forEach(q.choices, function (c) {
        c.isUserAnswer = false;
    });

    c.isUserAnswer = true;
};

另外,我建议您改变策略:

http://jsfiddle.net/hgxjv/5/

<input type="radio" name="response" value="{{choice.id}}" ng-model="question1.userChoiceId"/>

这样您就可以将{{question1.userChoiceId}}发送回服务器。


感谢您的回复。我知道您的第二个解决方案是理想的;然而,该应用程序实际上支持多种类型的问题,包括“选择所有适用的”问题--这就是每个选项存储值的原因。据我所知,您的第一个解决方案适用于在进行选择后更新模型,但不适用于显示从服务器检索到已经进行选择的模型。 - peteallen
2
啊,没错。您可以通过使用 ngChecked 来解决这个问题,不过您将不得不停止使用 true/false 作为字符串。您能做到吗?http://jsfiddle.net/hgxjv/6/ - Langdon
3
可以的!我之前试过使用ngChecked,但没有移除ngModel属性。在那种配置下它并不起作用,所以我一开始以为ngChecked和单选按钮不兼容。现在移除了ngModel属性,使用ngChecked,并将ngClick绑定到你的setChoiceForQuestion函数可以实现我的目标。谢谢你的帮助! - peteallen

12
 <label class="rate-hit">
     <input type="radio" ng-model="st.result" ng-value="true" ng-checked="st.result">
     Hit
 </label>
 &nbsp;&nbsp;
 <label class="rate-miss">
     <input type="radio" ng-model="st.result" ng-value="false" ng-checked="!st.result">
     Miss
 </label>

1
我认为这只能工作是因为“true”评估为真。如果您的“ng-value”是一个字符串,而不是对$scope中某个东西的引用,则必须将该字符串放在引号中。这就是我的情况。 - Jason Swett
这对我来说是最好的答案!谢谢,Ronel! - diwatu
只要定义了ng-model,这里就不需要使用ng-checked。 - Nico Westerdale

9
我试着将value="true"更改为ng-value="true",看起来它可以工作。
此外,要使您的示例中的两个输入都起作用,您必须为每个输入提供不同的名称--例如,response应更改为response1response2

1
不,名称可以相同。 - kumarharsh

1

0
如果您正在使用布尔变量来绑定单选按钮,请参考下面的示例代码。
<div ng-repeat="book in books"> 
<input type="radio" ng-checked="book.selected"  
ng-click="function($event)">                        
</div>

0

在fiddle中设置收音机的方式 - 共享相同的模型 - 如果您决定引用所有真值,只会导致最后一组显示选中的收音机。更可靠的方法将涉及为各个组提供自己的模型,并将值设置为收音机的唯一属性,例如id:

$scope.radioMod = 1;
$scope.radioMod2 = 2;

这里是新HTML的表示:

<label data-ng-repeat="choice2 in question2.choices">
            <input type="radio" name="response2" data-ng-model="radioMod2" value="{{choice2.id}}"/>
                {{choice2.text}}
        </label>

还有一个小提琴。


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