gaurav5430
gaurav5430

Reputation: 13892

Angular Material : make a md-radio-group required

I am working with Angular Material, I need to make a radio group required, so that the user has to select a radio button, before he can submit the form. So the form should be invalid while no radio button is selected.

this is the code

<form id="pipelineForm" name="pipelineForm" ng-submit="processForm()" flex layout="column" novalidate>
    <md-radio-group ng-model="parameters.selected" ng-required="true" name="analyzerRG" 
              <md-radio-button ng-value="choiceObj" ng-repeat="choiceObj in parameters.choices" ng-required>
              {{choiceObj.text}}
              </md-radio-button>
    </md-radio-group>
</form>

i have tried making individual <md-radio-button> required, giving name to the radio group and using ng-messages for required , but to no avail. When i check the md-radio-group in chrome element inspector, it always has the class="ng-valid ng-valid-required" .

I can probably check the parameters.selected property for validating the form on my own, but i would like if the correct classes are applied to the md-radio-group and so the form is automatically invalid.

P.S. : There is a similar issue on Angular Material Github, but it seems to be closed now and the suggestions do not seem to work for me.

Upvotes: 6

Views: 9865

Answers (3)

Kunal Panchal
Kunal Panchal

Reputation: 1059

Check the solution on CodePen (https://codepen.io/jakobadam/pen/xqZoBR) as mentioned in the issue thread

https://github.com/angular/material/issues/1305#issuecomment-350047026

<md-input-container class="md-input-has-value" 
       ng-class="{ 'md-input-invalid' : form.fruit.$invalid && form.$submitted }">
  <label class="md-required" translate>Fruit</label>

  <md-radio-group md-autofocus name="fruit" ng-model="fruit" layout="row" required>
    <md-radio-button value="Apple" class="md-primary">Apple</md-radio-button>
    <md-radio-button value="Banana"> Banana </md-radio-button>
    <md-radio-button value="Mango">Mango</md-radio-button>  
  </md-radio-group>

  <div ng-messages="form.fruit.$error">
    <div ng-message="required" translate>Yo. Select some fruit.</div>
  </div>
</md-input-container>

Upvotes: 4

John Rix
John Rix

Reputation: 6693

Regarding the lack of ng-messages, I am not 100% certain but I think this is down to ng-messages not being aware of custom controls like md-radio-group/md-radio-button. Here's an updated approach that uses an obscured text field attached to the same model value. This allows the messages to appear as expected.

Note that novalidate has been added to the form element here to stop browser native form validation from kicking in. Rather than disabling the submit button (which prevents any possibility of the messages being shown since there is no way to trigger the form validation), the ng-submit expression now checks myForm.$valid before invoking the submit method.

<html lang="en">

<head>
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.0/angular-material.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-animate.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-aria.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-messages.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.0/angular-material.min.js"></script>
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
    <script language="javascript">
        angular
            .module('firstApplication', ['ngAnimate', 'ngAria', 'ngMaterial', 'ngMessages'])
            .controller('myController', function($scope) {
                $scope.statuses = ['Planned', 'Confirmed', 'Cancelled'];
                $scope.options = ['Option 1', 'Option 2', 'Option 3', 'Option 4', '...'];
                $scope.submit = function(obj) {
                    // submit code goes here
                    console.log(obj);
                };
                $scope.reset = function() {
                    $scope.obj = {
                        status: ""
                    }
                }
                $scope.reset();
            });
    </script>
</head>

<body ng-app="firstApplication">

    <form name="myForm" ng-app="myApp" ng-controller="myController" class="container-fluid" ng-submit="myForm.$valid && submit(obj)" novalidate>
        <div class="row">
            <div class="col-xs-8">
                <md-input-container>
                    <md-radio-group id="status" ng-model="obj.status" class="">
                        <md-radio-button ng-repeat="s in statuses" ng-value="s">{{s}}</md-radio-button>
                    </md-radio-group>
                    <input type="text" ng-model="obj.status" name="status" style="max-height:0; opacity: 0; border: none" ng-required="true" aria-label="Status">
                    <div ng-messages="myForm.status.$error" role="alert">
                        <div ng-message="required">Status is required.</div>
                    </div>
                </md-input-container>
            </div>
        </div>
        <md-button type="button" ng-click="reset()">RESET</md-button>
        <md-button class="md-primary" type="submit">SUBMIT</md-button>
    </form>
</body>

</html>

Upvotes: 0

Je.
Je.

Reputation: 54

I try ng-disabled with material angular it works (in your case try to delete 'novalidate' attribut in your form balise)

Snippet:

<html lang="en">

<head>
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.0/angular-material.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-animate.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-aria.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-messages.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.0/angular-material.min.js"></script>
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
    <script language="javascript">
        angular
            .module('firstApplication', ['ngAnimate', 'ngAria', 'ngMaterial', 'ngMessages'])
            .controller('myController', function($scope) {
                $scope.statuses = ['Planned', 'Confirmed', 'Cancelled'];
                $scope.options = ['Option 1', 'Option 2', 'Option 3', 'Option 4', '...'];
                $scope.submit = function(obj) {
                    // submit code goes here
                    console.log(obj);
                };
                $scope.reset = function() {
                    $scope.obj = {
                        name: "",
                        myselect: "",
                        status: ""
                    }
                }
                $scope.reset();
            });
    </script>
</head>

<body ng-app="firstApplication">

    <form name="myForm" ng-app="myApp" ng-controller="myController" class="container-fluid" ng-submit="submit(obj)">
        <div class="row">
            <div class="col-xs-8">
                <md-input-container>
                    <label>Name</label>
                    <input name="name" id="name" ng-model="obj.name" ng-required="true">
                    <div ng-messages="myForm.name.$error">
                        <div ng-message="required">Campaign Name is required.</div>
                    </div>
                </md-input-container>
            </div>
            <div class="col-xs-8">
                <md-input-container>
                    <md-select name="myselect" id="myselect" placeholder="myselect" ng-model="obj.myselect" ng-required="true">
                        <md-option ng-repeat="o in options" ng-value="o">{{o}}</md-option>
                    </md-select>
                    <div ng-messages="myForm.myselect.$error">
                        <div ng-message="required">myselect is required.</div>
                    </div>
                </md-input-container>
            </div>
            <div class="col-xs-8">
                <md-input-container>
                    <md-radio-group name="status" id="status" ng-model="obj.status" ng-required="true" class="">
                        <md-radio-button ng-repeat="s in statuses" ng-value="s">{{s}}</md-radio-button>
                    </md-radio-group>
                    <div ng-messages="myForm.status.$error">
                        <div ng-message="required">myselect is required.</div>
                    </div>
                </md-input-container>
            </div>
        </div>
        <md-button type="button" ng-click="reset()">RESET</md-button>
        <md-button class="md-primary" type="submit" ng-disabled="myForm.$invalid">SUBMIT</md-button>
    </form>
</body>

</html>

Upvotes: -1

Related Questions