AngularJS - Binding radio buttons to models with boolean values
Asked Answered
S

7

206

I am having a problem binding radio buttons to an object whose properties have boolean values. I am trying to display exam questions retrieved from a $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
        }]
};   

With this example object, the "isUserAnswer: true" property does not cause the radio button to be selected. If I encapsulate the boolean values in quotes, it works.

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"
        }]
};   

Unfortunately my REST service treats that property as a boolean and it will be difficult to change the JSON serialization to encapsulate those values in quotes. Is there another way to set up the model binding without changing the structure of my model?

Here's the jsFiddle showing non-working and working objects

Smedley answered 6/6, 2013 at 19:9 Comment(0)
S
392

The correct approach in Angularjs is to use ng-value for non-string values of models.

Modify your code like this:

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

Ref: Straight from the horse's mouth

Sceptre answered 26/8, 2013 at 14:32 Comment(8)
just wanted to add an important side note: ng-value has to have the value without the curly braces {{}} Example: ng-value="choice2.id" vs value="{{choice2.id}}"Randarandal
Did not know data-ng-model/data-ng-value was a thing. Kept trying to use ng-model and ng-value with no success, but now with the data prefix things are working! Can you explain what exactly the "model-" prefix achieves? I don't see any documentation about it hereCaelian
You mean the data- prefix I think... The data- prefix is to make the HTML valid (although without that also all modern browsers handle the HTML correctly)Sceptre
I know the post is quite old but I got the same problem now. But when I use your solution and change the radio buttons all that were once selected are true and they don't switch back to false. Is there a solution for this? (problem also exists in OP's Fiddle)Zagreb
Can you post a fiddle?Sceptre
Have a look at the Angular Doc: docs.angularjs.org/api/ng/input/input%5Bradio%5DMarchelle
Can anyone explain why I had to the ng-checked attribute to this to get it to work? <input type="radio" name="hospitality" ng-model="model.hospitality" ng-value="true" ng-checked="model.hospitality===true" ng-required="model.hospitality===null"> (am using umbraco so forced into angular v1.1.4,perhaps that's it)Toms
I don't think ng-checked has anything to do with radio boxes. Although Angular 1.1.4 is ancient!Sceptre
C
21

That's an odd approach with isUserAnswer. Are you really going to send all three choices back to the server where it will loop through each one checking for isUserAnswer == true? If so, you can try this:

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

Alternatively, I'd recommend changing your tack:

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

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

That way you can just send {{question1.userChoiceId}} back to the server.

Casimir answered 6/6, 2013 at 19:38 Comment(3)
Thanks for your response. I know your second solution is ideal; however, the app actually supports multiple types of questions, including "check all that apply" questions -- hence the reason for the value being stored on each choice. From what I can tell, your first solution works for updating the model after a selection is made, but not for displaying the model retrieved from the server with a selection already made.Smedley
Ah, true. You can resolve that by using ngChecked, except you'll have to break away from using true/false as strings. Can you do that? jsfiddle.net/hgxjv/6Casimir
Yes, that works! I had tried using ngChecked before, but had not removed the ngModel attribute. It didn't work with that configuration, and I had assumed that it was because ngChecked wasn't compatible with radio buttons. Removing the ngModel attribute and using ngChecked and binding ngClick to your setChoiceForQuestion function achieves what I'm trying to do. Thank you for your help!Smedley
H
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>
Haynie answered 6/5, 2015 at 9:43 Comment(3)
I think this only works because true evaluates to true. If your ng-value is a string, for example, and not a reference to something in $scope, you'll have to put that string in quotes. That was the case for me.Prima
This is the best answer for me! Thanks, Ronel!Sil
ng-checked isn't needed here as long as ng-model is definedOvergrow
E
9

I tried changing value="true" to ng-value="true", and it seems to work.

<input type="radio" name="response2" data-ng-model="choice.isUserAnswer" ng-value="true" />

Also, to get both inputs to work in your example, you'd have to give different name to each input -- e.g. response should become response1 and response2.

Eddy answered 14/8, 2013 at 20:51 Comment(1)
No, names can be the same.Sceptre
F
1

You might take a look at this:

https://github.com/michaelmoussa/ng-boolean-radio/

This guy wrote a custom directive to get around the issue that "true" and "false" are strings, not booleans.

Fluter answered 6/6, 2013 at 20:14 Comment(0)
T
0

The way your radios are set up in the fiddle - sharing the same model - will cause only the last group to show a checked radio if you decide to quote all of the truthy values. A more solid approach will involve giving the individual groups their own model, and set the value as a unique attribute of the radios, such as the id:

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

Here is a representation of the new html:

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

And a fiddle.

Tengler answered 6/6, 2013 at 19:41 Comment(0)
S
0

if you are using boolean variable to bind the radio button. please refer below sample code

<div ng-repeat="book in books"> 
<input type="radio" ng-checked="book.selected"  
ng-click="function($event)">                        
</div>
Simaroubaceous answered 11/1, 2018 at 7:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.