2

Say I have a textbox validated by ngPattern that is currently valid. I now change the regex to one that does not match the textbox's value. Angular does not immediately pick up that the textbox is now invalid - the user must make a change (eg. type another letter) to cause validation against the new regex to occur.

A workaround is to force the parsing pipeline to run by setting the $viewValue to itself whenever the regex changes, eg:

View

<div ng-form="form">
    <input type="text" name="val" ng-model="myValue" ng-pattern="myRegex" />
</div>

Controller

// set a new regex for the ng-pattern directive and force re-validation
$scope.myRegex = new RegExp('^[a-z]$');
$scope.form.val.$setViewValue($scope.form.val.$viewValue); // yuck 

However, this seems like a big hack and I'm hoping there is a nicer way to do this without resorting to a custom directive.

Fiddle: http://jsfiddle.net/5jm2V/2/

Mike Chamberlain
  • 39,692
  • 27
  • 110
  • 158

1 Answers1

4

So far I have worked around this apparent limitation by moving the $setViewValue call into a directive, which at least adheres to the principle that controllers should not concern themselves with views:

// Causes immediate re-validation of the model when ngPattern's regex is changed,
// rather than waiting for the user to manually change the value.
myModule.directive('ngPatternImmediate', [
    function() {
        return {
            require: 'ngModel',
            link: function(scope, elm, attrs, ngModelCtrl) {

                scope.$watch(function() {
                    // watch for change of regex
                    return scope.$eval(attrs.ngPattern);
                }, function() {
                    // force parsing pipeline to run
                    ngModelCtrl.$setViewValue(ngModelCtrl.$viewValue);
                });
            }
        };
    }
]);

It can then be used like this:

<input type="text" ng-model="myValue" ng-pattern="myRegex" ng-pattern-immediate />

I am still interested if there is a better way to do this though.

Mike Chamberlain
  • 39,692
  • 27
  • 110
  • 158