How to show error messages for Checkbox set and Radio set using ng-messages?

Devner picture Devner · Jan 21, 2016 · Viewed 8.2k times · Source

I have been trying to validate Checkbox set and Radio set and show the error messages using ng-messages directive but it does not work out as expected. The ng-messages does not show the error message at all. I am populating error messages using an html file. Up until the errors are resolved, the submit button will be disabled in my form.

How can I show error messages for the Checkbox set and Radio set when:

  1. One option is not selected in Radio set?

  2. At least one option is not selected in Checkbox set?

  3. Scaling the check for the Checkbox set so that we can check at least 2 or more are checked, etc.?

Here's my form:

<form name="userForm" ng-submit="submitForm()" novalidate>
    <div class="form-group" ng-class="{ 'has-error' : userForm.subscribe.$invalid && !userForm.subscribe.$touched }">
        <label class="checkbox-inline">
            <input type="checkbox" id="subscribe1" value="option1" name="subscribe[]" ng-model="user.subscribe" required> 1
        </label>
        <label class="checkbox-inline">
            <input type="checkbox" id="subscribe2" value="option2" name="subscribe[]" ng-model="user.subscribe" required> 2
        </label>
        <label class="checkbox-inline">
            <input type="checkbox" id="subscribe3" value="option3" name="subscribe[]" ng-model="user.subscribe" required> 3
        </label>

        <div class="help-block" ng-messages="userForm.subscribe.$error" ng-show="userForm.subscribe.$invalid">
            <div ng-messages-include="home/messages.html"></div>
        </div>
    </div>

    <div class="form-group" ng-class="{ 'has-error' : userForm.gender.$invalid && !userForm.gender.$touched }">
        <div class="radio">
            <label>
                <input type="radio" name="gender" value="male" ng-model="user.gender" />
                male
            </label>
        </div>
        <div class="radio">
            <label>
                <input type="radio" name="gender" value="female" ng-model="user.gender" />
                female
            </label>
        </div>

        <div class="help-block" ng-messages="userForm.gender.$error" ng-show="userForm.gender.$invalid">
            <div ng-messages-include="home/messages.html"></div>
        </div>
    </div>
    <button type="submit" class="btn btn-primary btn-success " ng-disabled="userForm.$invalid">Submit</button>
</form>

messages.html

<span ng-message="required">This field is required</span>
<span ng-message="minlength">This field is too short</span>
<span ng-message="maxlength">This field is too long</span>
<span ng-message="required">This field is required</span>
<span ng-message="email">This needs to be a valid email</span>

controller.js

angular.module('myApp', ['ngRoute', 'ngAnimate', 'ngMessages']);

angular
    .module('myApp')
    .controller('HomeCtrl', HomeCtrl);

HomeCtrl.$inject = ['$scope'];

function HomeCtrl($scope) {
    $scope.userForm = {};
}

Payment Checkbox set:

<div class="form-group" ng-class="{ 'has-error' : userForm.payment.$invalid && userForm.payment.$touched }">
    <label class="checkbox-inline">
        <input type="checkbox" id="payment1" value="Visa" name="payment" ng-blur="doTouched()" ng-model="user.payment[1]" ng-required="!someSelected(user.payment)"> Visa
    </label>
    <label class="checkbox-inline">
        <input type="checkbox" id="payment2" value="Mastercard" name="payment" ng-blur="doTouched()" ng-model="user.payment[2]" ng-required="!someSelected(user.payment)"> Mastercard
    </label>
    <label class="checkbox-inline">
        <input type="checkbox" id="payment3" value="Cash" name="payment" ng-blur="doTouched()" ng-model="user.payment[3]" ng-required="!someSelected(user.payment)"> Cash
    </label>

    <div class="help-block" ng-messages="userForm.payment.$error" ng-show="userForm.payment.$invalid && userForm.payment.$touched">
        <div ng-messages-include="home/messages.html"></div>
    </div>
</div>

Answer

beaver picture beaver · Jan 21, 2016

Check this sample:

http://plnkr.co/edit/2w0lIf?p=preview

The check boxes list use the ng-required directive with the someSelected function (defined in the controller) which checks if at least one item is selected:

<div class="form-group" ng-class="{ 'has-error' : userForm.subscribe.$invalid && userForm.subscribe.$touched }">
    <label class="checkbox-inline">
        <input type="checkbox" id="subscribe1" value="option1" name="subscribe" ng-blur="doTouched()" ng-model="user.subscribe[1]" ng-required="!someSelected(user.subscribe)"> 1
    </label>
    <label class="checkbox-inline">
        <input type="checkbox" id="subscribe2" value="option2" name="subscribe" ng-blur="doTouched()" ng-model="user.subscribe[2]" ng-required="!someSelected(user.subscribe)"> 2
    </label>
    <label class="checkbox-inline">
        <input type="checkbox" id="subscribe3" value="option3" name="subscribe" ng-blur="doTouched()" ng-model="user.subscribe[3]" ng-required="!someSelected(user.subscribe)"> 3
    </label>

    <div class="help-block" ng-messages="userForm.subscribe.$error" ng-show="userForm.subscribe.$invalid && userForm.subscribe.$touched">
        <div ng-messages-include="messages.html"></div>
    </div>
</div>

The option button group is easier and use the ng-required directive with the condition !user.gender:

<div class="form-group" ng-class="{ 'has-error' : userForm.gender.$invalid && userForm.gender.$touched }">
    <div class="radio">
        <label>
            <input type="radio" name="gender" value="male" ng-model="user.gender" ng-required="!user.gender"/>
            male
        </label>
    </div>
    <div class="radio">
        <label>
            <input type="radio" name="gender" value="female" ng-model="user.gender" ng-required="!user.gender"/>
            female
        </label>
    </div>

    <div class="help-block" ng-messages="userForm.gender.$error" ng-if="userForm.gender.$touched">
        <div ng-messages-include="messages.html"></div>
    </div>
</div>

The ngBlur directive resolves the issue that a check boxes list become "touched" only when all the items in list are blurred, calling doTouched() function::

  $scope.doTouched = function() {
     $scope.userForm.subscribe.$setTouched();
  }

P.S. pay attention to correct names: userForm is the HTML name of the <form>, user is the name of the model to which is bound the form.