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

0

7 Answers 7

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

8
  • 13
    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}}"
    – Andi
    Oct 21, 2014 at 11:26
  • 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 here Dec 18, 2014 at 17:08
  • 3
    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)
    – kumarharsh
    Dec 19, 2014 at 6:07
  • 8
    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)
    – Dominik G
    Apr 16, 2015 at 10:05
  • Can you post a fiddle?
    – kumarharsh
    Apr 16, 2015 at 13:02
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.

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.
    – peteallen
    Jun 6, 2013 at 19:46
  • 2
    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/6
    – Langdon
    Jun 6, 2013 at 19:56
  • 3
    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!
    – peteallen
    Jun 6, 2013 at 21:33
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>
3
  • 1
    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. Feb 8, 2017 at 21:51
  • This is the best answer for me! Thanks, Ronel!
    – diwatu
    Feb 27, 2018 at 19:07
  • ng-checked isn't needed here as long as ng-model is defined Jun 20, 2018 at 21:43
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.

1
  • 1
    No, names can be the same.
    – kumarharsh
    Aug 26, 2013 at 16:53
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.

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

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>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.