Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angular select $touched validation

I have a form with select and a button that is enabled when the form is validated. It works fine with input box. However, it the $touched does not seem to be working properly for the select. The button is enabled even when select is touched. It is supposed to turn invalid when select is touched. It only turns invalid and the button is disabled when I select an option and then select the default value. I want it to work when select is touched and user the mouse pointer away. Here is my html:

<form role="form" name="frameVersionEditor" novalidate class="form-horizontal col-md-12">
<div class="row">
    <div class="form-group col-lg-2 col-lg-push-1" ng-class="{'has-error' : frameVersionEditor.distributor.$invalid && frameVersionEditor.distributor.$touched}">
        <label>Distributor</label>
        <select name="distributor" data-ng-model="myDistr" data-ng-options="distributors.key as distributors.value for distributors in distributorOptions" class="form-control" required>
            <option value="">Select Distributor</option>
        </select>
        <span ng-show="frameVersionEditor.distributor.$error.required && frameVersionEditor.distributor.$touched" class="help-block">Please select a distributor</span>
    </div>
</div>
</form>
<button data-ng-click="generate()" ng-disabled="frameVersionEditor.$invalid">Generate</button>

Here is my controller:

var myApp = angular.module('myApp',[]);

myApp.controller('myController', ['$scope', function($scope) {
      $scope.myDistr = [];
      $scope.distributors =
            [
                {
                    'key': '0',
                    'value': 'A'
                },
                {
                    'key': '1',
                    'value': 'B'
                },
                {
                    'key': '2',
                    'value': 'C'
                }
            ];
      $scope.generate = function() {
      //Do something
      };
}]);
like image 366
Gantavya Avatar asked Mar 20 '15 21:03

Gantavya


People also ask

How do I add validation in template-driven form?

To add validation to a template-driven form, you add the same validation attributes as you would with native HTML form validation. Angular uses directives to match these attributes with validator functions in the framework.

What is dirty in form validation?

ng-dirty: The ng-dirty class tells that the form has been made dirty (modified ) by the user. It returns true if the user has modified the form. Return type: Return Boolean True if the form/input field is modified by the user else it returns False.


2 Answers

I had much the same issue just a short time ago. I solved it by adding a few things to the select field and another entry to the array of possible selections.

First, you want to add an empty or invalid selection to the list of possible selections, the best place is in the [0] slot and you'll see why further down.

vm.distributors = [ "Select Distributor", "A", "B", "C" ];

Next, you need to add and update some Angular Directives for your select field. You want the ng-valid to tell Angular what is acceptable here. You also need to specify that you are starting the field with a "select something else" value and that it is not valid for that value to be selected during submit. Adding a name and id are generally best practice items. The last bit to add is the ng-required directive, since you used novalidate on the form, but it is required that this form item change to something valid. The end result is below:

<div class="form-group col-lg-2 col-lg-push-1" ng-class="{'has-error' : vm.myDistr == vm.distributors[0] && frameVersionEditor.$dirty
    || frameVersionEditor.distributor.$pristine && frameVersionEditor.distributor.$touched}">
      <label>Distributor</label>
      <select data-ng-model="vm.myDistr" id="myDistr" name="myDistr" ng-init="vm.distributors[0]" class="select form-control skinny" ng-required="true"
        data-ng-options="d for d in vm.distributors" ng-valid="vm.myDistr != vm.distributors[0]"></select>
        <p class="required" ng-show="vm.myDistr == vm.distributors[0]">&#42;</p>
        <p class="good" ng-show="vm.myDistr != vm.distributors[0]">&#10004;</p>
      <span ng-show="vm.myDistr == vm.distributors[0] && frameVersionEditor.$dirty || frameVersionEditor.distributor.$pristine
      && frameVersionEditor.distributor.$touched" class="help-block">Please select a distributor</span>

This also was updated to illustrate the simplest implementation (since you are using 0-4 as keys, you don't really need them, just use a basic array). I also changed your code to coincide with John Papa's best practices and added in a red asterisk (for invalid selections) and a green check mark (for a correct selection), as is another good practice (show success as well as failure) in the case of non-English-speaking users.

You also do not need the beginning option you specified originally since my updates handle that nicely.

By request, here is a Plunker.

I hope this helps.

-C§

like image 134
CSS Avatar answered Oct 29 '22 12:10

CSS


I have made up this fiddle and everything seems to work fine.

<div ng-app="myApp" ng-controller="myController">
     <h1>Select a Distributor</h1>
    <form name="form" class="form-horizontal col-md-12" novalidate>
        <div class="row">
            <div class="form-group col-lg-2 col-lg-push-1" ng-class="{ 'has-error': form.distributor.$invalid && form.distributor.$touched }">
                <label>Distributor</label>
                <select name="distributor" ng-model="mySelection" ng-options="d.key as d.value for d in myDistr" class="form-control" required>
                    <option value="">Select Distributor</option>
                </select>
                <span ng-show="form.distributor.$error.required" class="help-inline">Please select a distributor</span>
            </div>
        </div>
    </form>
    <hr/><hr/>
    <button class="btn btn-primary" data-ng-click="generate()" ng-disabled="form.$invalid  || form.distributor.$touched">Generate</button>
</div>

I have the suspect that maybe the $touched event is not what you think.

Please give me some feedback if I'm wrong!

like image 22
Kutyel Avatar answered Oct 29 '22 13:10

Kutyel