ng-repeat を使用してラジオ ボタン リストをレンダリングするために使用しているオブジェクトの配列があります。私の質問は、各質問の選択された値をバインドし、それらを何らかのタイプのモデルにバインドする方法です。これは私がこれまでに持っているプランカーですhttp://plnkr.co/edit/oXr6Un?p=previewですが、コードはラジオボタンリストをループして選択した値を取得するだけです。ユーザーが回答を選択したときに、そのオブジェクトがバインドされ、そのプロパティが変更されることを本当に望んでいます。これどうやってするの?私はAngularjsを初めて使用することを理解してください。ありがとうございました、ck
3 に答える
@Maxが上で言ったように、入力に ng-model を設定する必要があります...しかし、それだけではありません。 私はあなたのプランクをフォークして更新し、機能するものを示しました
いくつかの注意事項:
- 「showAnswers」にサービスは必要ありませんでした。Angular を使用している間は、JQuery を介して入力から値を取得する必要はありません。
- 入力に ng-model を追加する必要がありましたが、入力が独自の子スコープを持つ の
$parent.answer
内部にあったため、ng-model で使用する必要があります。ng-repeat
for=""
ラベル付けしている入力をラップするラベルは必要ありません。
重要な変更:
<li ng-repeat="answer in question.answers">
<label>
<input type="radio" ng-model="$parent.question.selectedAnswer"
value="{{ answer.answerText }}" name="quest_{{$parent.$index}}_answers" />{{ answer.answerText }}</label>
</li>
と
$scope.selectedAnswers = function(){
var answers = [];
angular.forEach($scope.questions, function(question) {
answers.push(question.selectedAnswer);
});
return answers;
};
お役に立てば幸いです。
入力に ng-model を設定する必要があります (http://docs.angularjs.org/api/ng.directive:input.radio)。これにより、双方向のデータバインディングが得られます。
ディレクティブ バージョンの記述方法は次のとおりです。
モデルを簡素化しました。各質問とその可能な回答は次のようになります。
{ question: "Why is the sky blue?",
answerChoices: [ "blah blah 1", "Rayleigh scattering", "blah blah 3" ] },
このような各オブジェクトに、ラジオ ボタンを介して「answer」要素を動的に追加します。それについては後で詳しく説明します。
工場を合理化しました。オブジェクトの配列を返すだけです。
.factory('questionFactory', function() {
return [
{ question: ...
コントローラーはこれを簡単に実行できるようになりました。
$scope.questions_and_answers = questionFactory;
これで、モデルが定義されました。次に、必要なディレクティブと、各ディレクティブのテンプレートと動作について考えたいと思います。クイズ、質問、回答の 3 つのディレクティブは保持しましたが、回答の名前を possibleAnswer に変更しました。
個人的な選択の問題として、「quiz」ディレクティブに質問と回答の主要な構造を含める方がよいと考えたので、回答の ng-repeat を質問ディレクティブのテンプレートからクイズに移動しました。ディレクティブのテンプレート。quiz 要素も残しましたが、個人的には
<li ng-repeat ...> something here </li>のような見慣れない<li answer ng
の代わりに、より親しみやすいマークアップ構造を見たいので、 question と possibleAnswer を属性に変更しました
-繰り返す ...></li>
.directive('quiz', function() {
...
template:'<ul class="unstyled">' +
'<li ng-repeat="item in questionsAndAnswers">' +
'<span question="{{item.question}}"></span>' +
'<ul class="unstyled">' +
'<li ng-repeat="possibleAnswer in item.answerChoices">' +
'<span possible-answer="{{possibleAnswer}}" item=item id="{{$parent.$index}}"></span>' +
'</li>' +
'</ul>' +
'</li></ul>'
質問ディレクティブ テンプレートは、質問のみを処理するようになりました。
template:'<strong class="question">{{ question }}</strong>'
そして、 possibleAnswer ディレクティブは、可能な答えを1つだけ扱います(すでに持っているように):
template: '<label><input type="radio" ng-value="possibleAnswer"' +
' ng-model="item.answer" name="q{{id}}" />{{possibleAnswer}}</label>'
これらのテンプレートでは多くのことが行われています。私が行ったことを理解するために、ディレクティブ スコープの継承について説明する必要があります。私はすべてのディレクティブに分離スコープを使用しています (つまり、分離スコープscope: { ... }
は通常、再利用可能なコンポーネントに最適な選択だからです)。(他の選択肢については、こちらを参照してください。) 質問と回答の選択肢はディレクティブによって変更されないため、双方向バインディングは必要なく、一方向バインディング (親スコープ -> ディレクティブ スコープ) のみが必要になるため、「@」は適切な選択です:
.directive('question', function() {
...
scope: { question: '@' },
.directive('possibleAnswer', function() {
...
scope: { possibleAnswer: '@', ... },
親スコープからの質問と可能な回答の評価済みコピーをディレクティブに渡す必要があるため、{{}} 表記を使用します。
<span question="{{item.question}}">
<span possible-answer="{{possibleAnswer}}" ...
トリッキーな部分です。単一の質問に関連付けられたラジオ ボタンはすべて同じ名前である必要があり、@Max が既に述べたように、すべてのラジオ ボタンに対して親モデルに戻る双方向バインディングが必要です。質問IDの一方向バインディングを使用して「同じ名前」の問題を解決しました。これは実際にはng-repeat question $indexです。
<span possible-answer="{{possibleAnswer}}" id="{{$parent.$index}}" ...>
.directive('possibleAnswer', function() {
...
scope: { id: '@', ... },
...
template: '...<input type="radio" ... name="q{{id}}"...
同じ質問 ID/インデックス (回答選択肢 ID/インデックスではない) が必要なため、$parent を使用して質問スコープを検索し、その ng-repeat $index、つまり $parent.$index を取得します。別の方法は、メイン モデルの各オブジェクトに「id」プロパティを追加し (お持ちのように)、それをディレクティブに渡すことです。
<span possible-answer="..." id="{{item.id}}" ...>
(実際には、以下で 'item' をディレクティブに渡していることがわかるので、そのような id プロパティは無料で提供されるため、"id='...'" は必要ありません。モデルをできるだけ単純にすることを好みます。オブジェクトの配列を使用しているため、配列インデックス (ng-repeat $index) で十分なので、メイン モデルでは id プロパティを使用しませんでした。
双方向のデータ バインディングを取得するには、「=」を使用する必要があります。メイン モデルのオブジェクトに動的に追加する新しい「answer」プロパティにバインドします (これについては前に説明しました)。そのため、回答の選択肢をループしている間に、モデル内の適切なオブジェクトへの参照が必要です。次に、この新しい動的プロパティを ng-model に割り当てます。
<li ng-repeat="item in questionsAndAnswers">' + // pass this 'item' to possibleAnswer
...
'<ul ..>' +
'<li ng-repeat="possibleAnswer in item.answerChoices">' +
<span possible-answer="{{possibleAnswer}}" item=item ...">
.directive('possibleAnswer', function() {
...
scope: { item: '=', ... },
...
template: '...<input type="radio" ... ng-model="item.answer" ...' // new property
注:入力ラジオ API ページに関する Disqus のコメントによると、「値」の代わりに「ng-value」を使用する必要があります。
template: '...<input type="radio" ng-value="possibleAnswer" ...
quiz 要素ディレクティブについては、特定のスコープ プロパティが親スコープに存在すると仮定するよりも、モデルを渡す方がコンポーネントの再利用性が高いと思います。したがって、次のようになります。
<quiz questions-and-answers=questions_and_answers></quiz>
possibleAnswer ディレクティブはモデルを変更する必要があるため、ここでも双方向バインディングを使用する必要があるため、「=」:
.directive('quiz', function() {
...
scope: { questionsAndAnswers: '='},
最後に、コントローラー: selectedAnswer() 関数を削除し、index.html の ng-repeat をわずかに変更して、同じ機能を取得しました。
<div ng-repeat="item in questions_and_answers">
A{{$index}}: {{item.answer}}
そのため、コントローラーは素晴らしく薄い (推奨されるベスト プラクティス) -- 1 行のコードです。
jQuery の使用がなかったので、削除しました。(bootstrap.jsの使用も見られず、エラーがスローされていたので、それも削除しました。)
これは私にとって素晴らしい演習でした。OP に感謝します。(この回答が長すぎて申し訳ありません。私は夢中になりましたが、すべてを書き留めることで、いくつかのことが明確になりました。)