NgPattern not working

I want to check the input using ngPattern, based on the selection choice. It works after the first selection, but any subsequent selection is not bound correctly.

Here's jsFiddle for reference: http://jsfiddle.net/PLRf5/17/

<html> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js"></script> <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" /> <style> .field-validation-error { color: red; } </style> </head> <body> <div class="container form-group" ng-app="mod1" ng-controller="ctrl1"> <p> ng-pattern binding is not updating: Enter in 'asdf' then click Cuba. ngPattern should update and you should not see "Bad Format". </p> <div ng-form="genericAddressEntry"> <div class="form-group" data-ng-class="{ 'has-error': genericAddressEntry.country.$invalid }"> <label for="country">Country</label> <select name="country" class="form-control" data-ng-model="selectedCountry" data-ng-options="country as country.name for country in countries" data-ng-required="true" > </select> </div> <div class="clearFix" ng-bind="selectedCountry | countryToPostalCodeRegex"></div> <div class="form-group " data-ng-class="{ 'has-error': genericAddressEntry.postalCode.$invalid }"> <label for="postalCode">Zip Code</label> <input name="postalCode" type="text" class="form-control" data-ng-model="editAddress.postalCode" data-ng-required="selectedCountry.requiresPostal" ng-pattern="selectedCountry | countryToPostalCodeRegex" maxlength="12" /> <span class="field-validation-error" data-ng-show="genericAddressEntry.postalCode.$error.pattern">Bad Format</span> <span class="field-validation-error" data-ng-show="genericAddressEntry.postalCode.$error.required">Required</span> </div> </div> </div> <script> //module: angular.module('mod1', []) .controller('ctrl1', ['$scope', function ($scope) { // $scope.editAddress = { postalCode: "12345" }; $scope.countries = [ { name: 'United States', requiresPostal: true, postalRegEx: '^[0-9]{5}([-]?[0-9]{4})?$' }, //{ name: 'Canada', requiresPostal: true, postalRegEx: '^[a-yA-Y]\d[a-zA-Z]( )?\d[a-zA-Z]\d$' }, { name: 'Cuba', requiresPostal: false, postalRegEx: undefined }]; $scope.selectedCountry = $scope.countries[0]; }]) .filter('countryToPostalCodeRegex', [function () { var allowAllRegex = new RegExp("^.*"); var escapeRegex = function (str) { return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); } return function (country) { if (!country) { return allowAllRegex; } if (!country.requiresPostal) { return allowAllRegex; } if (!country.postalRegExObj) { country.postalRegExObj = new RegExp(escapeRegex(country.postalRegEx), "i"); } return country.postalRegExObj; }; }]); </script> </body> </html> 
+6
source share
3 answers

Angular does not currently control change attributes; it only controls related values. There are a couple of Angular questions that discuss this further NgMinlength and NgMaxlength - sets the length value dynamically does not work and the input does not look ngPattern value for changes . Two key caitp comments:

The generic Angular template does not respond to actual changes in the attribute value, but rather respond to changes in the associated value.

and

The fact is that at present the template does not come from the analyzed variable expression / scope, it is just a string literal rotated into a regular expression, therefore, observing changes in this means essentially looking at the value of the DOM attribute for a change. I think I mentioned that on another issue regarding this a few weeks ago. Viewing changes to the actual DOM attribute is quite different from what Angular typically does.

Given these issues and considering how Angular implements ngPattern , one way to deal with this is to add a directive that monitors Angular eval() the ngPattern attribute for changes. If he sees a change, he can evaluate the regular expression ngPattern and setValidity .

This gives us dynamic monitoring of attribute values. Here's the directive:

 .directive('updatePattern', function() { return { require: "^ngModel", link: function(scope,element,attrs,ctrl) { scope.$watch(function() { // Evaluate the ngPattern attribute against the current scope return scope.$eval(attrs.ngPattern); }, function(newval, oldval) { //Get the value from `ngModel` value = ctrl.$viewValue; // And set validity on the model to true if the element // is empty or passes the regex test if (ctrl.$isEmpty(value) || newval.test(value)) { ctrl.$setValidity('pattern', true); return value; } else { ctrl.$setValidity('pattern', false); return undefined; } }); } } }); 

And we will add our new update-pattern directive in html:

 <input name="postalCode" type="text" class="form-control" data-ng-model="editAddress.postalCode" data-ng-required="selectedCountry.requiresPostal" ng-pattern="selectedCountry | countryToPostalCodeRegex" maxlength="12" update-pattern /> 

working violin

+7
source

I have an easy way to solve this problem.

Using pattern instead of ng-pattern .

If you had angular source code, you will find that pattern and ng-pattern are the same directive.

There are two different meanings between pattern and ng-pattern :
1. angular will observe template changes. (What we need!)
2. angular will add ^ and add '$' to the pattern

 $scope.regex = '\\d\\d'; //angular will convert this to ^\d\d$ $scope.UPPERCASE = '\\D\\D'; 

HTML:

 <input name="test" pattern="regex"> <!-- I can use filter to change my wrong UPPERCASE regex to correct.--> <input name="test2" pattern="UPPERCASE | lowercase"> 
+4
source

@KayadDave's solution is perfect, but you can use a workaround: call $ setViewValue manually to get ng-pattern to evaluate:

 <!-- Add ng-change function --> <select name="country" class="form-control" data-ng-model="selectedCountry" data-ng-options="country as country.name for country in countries" data-ng-required="true" data-ng-change="updatePattern()" > </select> 

In the controller:

 $scope.updatePattern = function() { var postalCode = $scope.genericAddressEntry.postalCode; postalCode.$setViewValue(postalCode.$viewValue); }; 
+1
source

All Articles