AngularJS has some pretty nice built in form validation, but for some reason there is no out of the box support for validating radio buttons.
So when handeling a requirement where the end users had to fill out multiple choice questionnaires, I had to come up with something elegant to check if all the questions were answered.
The backend service returns questionnaires in JSON like this:
[code language=”javascript”]
"questions":[
{
"id":1,
"text":"Question one",
"answers":[{"id":2,"text":"Answer A"},{"id":3,"text":"Answer B"}],
"selectedAnswer":null
},
{
"id":4,
"text":"Question two",
"answers":[{"id":5,"text":"Answer X"},{"id":6,"text":"Answer Y"}],
"selectedAnswer":null
}
]
[/code]
The first we put the questions on the scope and then we add the following code to the HTML template
[code language=”html”]
<fieldset class="listing" ng-repeat="question in applicationKnowledge.questions">
<div class="control-group">
<label class="control-label">{{$index + 1}}. {{question.text}}</label>
<div class="controls">
<label class="radio" ng-repeat="answer in question.answers">
<input type="radio" ng-model="question.selectedAnswer" name="answer-for-question-{{question.id}}" value="{{answer.id}}">
<span>{{answer.text}}</span>
</label></div>
</div></fieldset>
[/code]
This renders the questions nicely, it also binds the id of the selected answer for each seperate question, but we still do not have any validation. So in the controller we add a function that is triggered when the form is submitted.
[code language=”javascript”]
function allQuestionsAnswered = function() {
for(var i = 0 ; i < $scope.questions.length ; i++) {
if(! $scope.questions[i].selectedAnswer) {
return false;
}
}
return true;
}
$scope.onSubmit = function() {
if(allQuestionsAnswered()) {
delete $scope.validationFailed;
// code to go to the next step here
} else {
$scope.validationFailed = true;
}
}
[/code]
So now we have code that validates if all our radio buttons are checked, but the end user still does not see which questions he missed when submitting the form. So we add an ng-class driective to the HTML like so:
[code language=”html”]
<fieldset class="listing" ng-repeat="question in applicationKnowledge.questions">
<div class="control-group" ng-class="{‘error’: !question.selectedAnswer && validationFailed}">
<label class="control-label">{{$index + 1}}. {{question.text}}</label>
<div class="controls">
<label class="radio" ng-repeat="answer in question.answers">
<input type="radio" ng-model="question.selectedAnswer" name="answer-for-question-{{question.id}}" value="{{answer.id}}">
<span>{{answer.text}}</span>
</label></div>
</div></fieldset>
[/code]
And there you go, the ng-class directive adds the CSS class error to each individual question if the form validation has triggered, and if that individual question was not answered yet.
This might not be ideal since it does require a bit of custom validation javascript code, but I hope it helps anyone else out there looking to do validation on their radio buttons using AngularJs.