AngularJS - Liaison des boutons radio aux modèles avec des valeurs booléennes

199

J'ai un problème pour lier les boutons radio à un objet dont les propriétés ont des valeurs booléennes. J'essaie d'afficher les questions d'examen récupérées à partir d'une ressource $.

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

Avec cet exemple d'objet, la propriété "isUserAnswer: true" n'entraîne pas la sélection du bouton radio. Si j'encapsule les valeurs booléennes entre guillemets, cela fonctionne.

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

Malheureusement, mon service REST traite cette propriété comme un booléen et il sera difficile de modifier la sérialisation JSON pour encapsuler ces valeurs entre guillemets. Existe-t-il une autre façon de configurer la liaison de modèle sans modifier la structure de mon modèle?

Voici le jsFiddle montrant les objets qui ne fonctionnent pas et qui fonctionnent

peteallen
la source

Réponses:

376

L'approche correcte dans Angularjs est à utiliser ng-valuepour les valeurs non-string des modèles.

Modifiez votre code comme ceci:

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

Réf: Directement de la bouche du cheval

kumarharsh
la source
12
je voulais juste ajouter une note latérale importante: la valeur ng doit avoir la valeur sans les accolades {{}} Exemple: valeur ng = "choix2.id" vs valeur = "{{choix2.id}}"
Andi
Oui, c'est exact, car la valeur ng est évaluée dans cette portée
kumarharsh
@Andi merci pour cette note, cela m'a fait gagner du temps pour le débogage!
Roy Milder
3
Vous voulez dire le préfixe de données je pense ... Le préfixe de données est de rendre le HTML valide (bien que sans cela aussi tous les navigateurs modernes gèrent correctement le HTML)
kumarharsh
6
Je sais que le message est assez ancien, mais j'ai le même problème maintenant. Mais lorsque j'utilise votre solution et que je modifie les boutons radio, tout ce qui a été sélectionné est vrai et ne revient pas à faux. Y a-t-il une solution à cela? (le problème existe aussi dans OP's Fiddle)
Dominik G
21

C'est une étrange approche avec isUserAnswer. Allez-vous vraiment renvoyer les trois choix au serveur où il passera en revue chacun d'eux pour vérifier isUserAnswer == true? Si oui, vous pouvez essayer ceci:

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

Alternativement, je recommanderais de changer votre virement:

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

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

De cette façon, vous pouvez simplement renvoyer {{question1.userChoiceId}}au serveur.

Langdon
la source
Merci pour votre réponse. Je sais que votre deuxième solution est idéale; cependant, l'application prend en charge plusieurs types de questions, y compris les questions «cochez toutes les réponses qui s'appliquent» - d'où la raison pour laquelle la valeur est stockée dans chaque choix. D'après ce que je peux dire, votre première solution fonctionne pour mettre à jour le modèle après une sélection, mais pas pour afficher le modèle récupéré du serveur avec une sélection déjà effectuée.
peteallen
2
Ah, c'est vrai. Vous pouvez résoudre ce problème en utilisant ngChecked, sauf que vous devrez éviter d'utiliser true / false comme chaînes. Peux-tu faire ça? jsfiddle.net/hgxjv/6
Langdon
3
Oui ça marche! J'avais déjà essayé d'utiliser ngChecked, mais je n'avais pas supprimé l'attribut ngModel. Cela ne fonctionnait pas avec cette configuration, et j'avais supposé que c'était parce que ngChecked n'était pas compatible avec les boutons radio. La suppression de l'attribut ngModel et l'utilisation de ngChecked et la liaison de ngClick à votre fonction setChoiceForQuestion accomplissent ce que j'essaie de faire. Merci de votre aide!
peteallen
10
 <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>
Ronel Gonzales
la source
Je pense que cela ne fonctionne que parce truequ'il est vrai. Si votre ng-valueest une chaîne, par exemple, et non une référence à quelque chose $scope, vous devrez mettre cette chaîne entre guillemets. C'était le cas pour moi.
Jason Swett
C'est la meilleure réponse pour moi! Merci, Ronel!
Gisway
ng-vérifié n'est pas nécessaire ici tant que le modèle ng est défini
Nico Westerdale
7

J'ai essayé de changer value="true"pour ng-value="true", et cela semble fonctionner.

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

De plus, pour que les deux entrées fonctionnent dans votre exemple, vous devez donner un nom différent à chaque entrée - par exemple, responsedevrait devenir response1et response2.

seung
la source
1
Non, les noms peuvent être les mêmes.
kumarharsh
0

La façon dont vos radios sont configurées dans le violon - partageant le même modèle - fera que seul le dernier groupe affichera une radio vérifiée si vous décidez de citer toutes les valeurs véridiques. Une approche plus solide impliquera de donner aux groupes individuels leur propre modèle et de définir la valeur comme un attribut unique des radios, comme l'id:

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

Voici une représentation du nouveau html:

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

Et un violon.

rGil
la source
0

si vous utilisez une variable booléenne pour lier le bouton radio. veuillez vous référer à l'exemple de code ci-dessous

<div ng-repeat="book in books"> 
<input type="radio" ng-checked="book.selected"  
ng-click="function($event)">                        
</div>
Sahitya M
la source