AngularJS - Vinculando botões de opção a modelos com valores booleanos

199

Estou tendo um problema ao vincular botões de opção a um objeto cujas propriedades possuem valores booleanos. Estou tentando exibir perguntas do exame recuperadas de um recurso $.

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

Com este objeto de exemplo, a propriedade "isUserAnswer: true" não faz com que o botão de opção seja selecionado. Se eu encapsular os valores booleanos entre aspas, ele funcionará.

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

Infelizmente, meu serviço REST trata essa propriedade como um valor booleano e será difícil alterar a serialização JSON para encapsular esses valores entre aspas. Existe outra maneira de configurar a ligação do modelo sem alterar a estrutura do meu modelo?

Aqui está o jsFiddle mostrando objetos que não estão funcionando e estão funcionando

peteallen
fonte

Respostas:

376

A abordagem correta no Angularjs é usar ng-valuepara valores não string de modelos.

Modifique seu código assim:

<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: Diretamente da boca do cavalo

kumarharsh
fonte
12
só queria adicionar uma observação importante: ng-value deve ter o valor sem as chaves {{}} Exemplo: ng-value = "choice2.id" vs value = "{{choice2.id}}"
Andi
Sim, isso é correto, como o ng valor é avaliado nesse âmbito
kumarharsh
@ Andrei obrigado por esta observação, ele me salvou um pouco de depuração!
Roy Milder 26/10
3
Você quer dizer o prefixo de dados, eu acho ... O prefixo de dados é tornar o HTML válido (embora sem isso todos os navegadores modernos também manejem o HTML corretamente)
kumarharsh
6
Sei que o post é bastante antigo, mas agora tenho o mesmo problema. Mas quando eu uso sua solução e altero os botões de opção, todos os que foram selecionados são verdadeiros e eles não retornam para falso. Existe uma solução para isso? (problema também existe no violino do OP)
Dominik G
21

Essa é uma abordagem estranha isUserAnswer. Você realmente enviará as três opções de volta ao servidor, onde ele percorrerá cada uma delas procurando isUserAnswer == true? Nesse caso, você pode tentar o seguinte:

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

Como alternativa, recomendo alterar sua tática:

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

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

Dessa forma, você pode simplesmente enviar de {{question1.userChoiceId}}volta para o servidor.

Langdon
fonte
Obrigado pela sua resposta. Eu sei que sua segunda solução é ideal; no entanto, o aplicativo realmente oferece suporte a vários tipos de perguntas, incluindo perguntas "marque todas as que se aplicam" - daí o motivo para o valor ser armazenado em cada opção. Pelo que sei, sua primeira solução funciona para atualizar o modelo após a seleção, mas não para exibir o modelo recuperado do servidor com uma seleção já feita.
peteallen
2
Ah verdade. Você pode resolver isso usando ngChecked, exceto que precisará interromper o uso de true / false como strings. Você pode fazer aquilo? jsfiddle.net/hgxjv/6
Langdon,
3
Sim, isso funciona! Eu tentei usar o ngChecked antes, mas não havia removido o atributo ngModel. Não funcionou com essa configuração, e eu assumi que era porque o ngChecked não era compatível com os botões de opção. Remover o atributo ngModel e usar ngChecked e vincular o ngClick à sua função setChoiceForQuestion alcança o que estou tentando fazer. Obrigado pela ajuda!
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
fonte
Eu acho que isso só funciona porque trueavalia como verdadeiro. Se você ng-valueé uma string, por exemplo, e não uma referência a algo $scope, precisará colocar essa string entre aspas. Esse foi o meu caso.
Jason Swett
Esta é a melhor resposta para mim! Obrigado, Ronel!
Gisway
ng-despachada não é necessário aqui enquanto NG-modelo é definido
Nico Westerdale
7

Tentei mudar value="true"para ng-value="true", e parece funcionar.

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

Além disso, para que ambas as entradas funcionem no seu exemplo, você teria que dar um nome diferente a cada entrada - por exemplo, responsedeveria se tornar response1e response2.

seung
fonte
1
Não, os nomes podem ser os mesmos.
precisa saber é o seguinte
0

A maneira como seus rádios são configurados no violino - compartilhando o mesmo modelo - fará com que apenas o último grupo mostre um rádio marcado se você decidir citar todos os valores de verdade. Uma abordagem mais sólida envolverá dar aos grupos individuais seu próprio modelo e definir o valor como um atributo exclusivo dos rádios, como o id:

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

Aqui está uma representação do novo html:

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

E um violino.

rGil
fonte
0

se você estiver usando a variável booleana para vincular o botão de opção. consulte o código de exemplo abaixo

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