ng-pattern not working with angular ui datepicker
angular-ui, angularjs
Solution
As I mentioned in my comment, what is happening is that the `datepicker` directive is changing the model value from a `String` to a `Date` object. When `ngPattern` tried to validate the `Date` object it will fail because the string value of a `Date` is not going to match the pattern that you are using.
What you can do is create your own directive that hooks into the $parsers of the ngModelController to run your pattern check and then call `$setValidity()` based on what the value is. `$parsers` is actually built for this type of functionality where you want to run your own custom validation on a `ngModel` value.
Following these bullets is a directive that will accomplish the functionality that you want. I want to explain the logic in the directive before I show you the code:
- In order to add your own $parser you have to add a require for `ngModel` in your directive definition so that you can access the `ngModelController`
- Because RegExp expects the pattern argument without the beginning and trailing slash, I removed them in the pattern directive argument
- `datepicker` changes the model value from a `String` to a `Date`. Since `datepicker` uses `unshift` to add it's $parser function to the beginning of the `$parsers` array, we also need to use `unshift` to put our $parser before `datepicker`'s $parser.
- As you mentioned, the `datepicker` directive will take any value that it can parse into a date and use that for the model. In order to make sure that only dates which match the pattern are used, I'm returning `undefined` (as specified in the docs) for dates that don't match the pattern. I'm not doing this check for values that come in as a `Date` object since that means that it was chosen using the `datepicker` widget.
- As I just alluded to in the previous bullet, I'm not doing the validity check if the value is already a `Date` object since that means that it was chosen using the `datepicker` widget and that means that it was a valid date.
directive code
app.directive('awDatepickerPattern',function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope,elem,attrs,ngModelCtrl) {
var dRegex = new RegExp(attrs.awDatepickerPattern);
ngModelCtrl.$parsers.unshift(function(value) {
if (typeof value === 'string') {
var isValid = dRegex.test(value);
ngModelCtrl.$setValidity('date',isValid);
if (!isValid) {
return undefined;
}
}
return value;
});
}
};
});
html - make sure that you don't forget to remove the beginning and trailing slash in the regex definition:
aw-datepicker-pattern="^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$"
And here is an updated plunker with my code.
So why again didn't ng-pattern work?
In case you didn't notice the root cause for why ng-pattern doesn't work when used with the `datepicker` directive is because the `datepicker` directive adds it's own ngModelController $parser to the beginning of the $parsers array by using `unshift`, which changes the model value from a `String` to a `Date`.
Problem
I want to use ng-pattern to further enforce the date format on an input field using Angular UI datepicker. The problem is when I do this it's always showing invalid. ``` <p class="input-group"> <input type="text" datepicker-popup="MM/dd/yyyy" is-open="opened" close-text="Close" ng-model="someDate" class="form-control" placeholder="mm/dd/yyyy" ng-pattern="/^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$/" required /> <span class="input-group-btn"> <button type="button" class="btn btn-default" ng-click="open($event)"> <i class="glyphicon glyphicon-calendar"></i> </button> </span> </p> ``` If I apply the same ng-pattern to a plain input field (no datepicker), it works as expected. There seems to be a conflict but I'm not sure what it is. Any ideas? Update: Here is a simple plunker to illustrate the issue as requested. After some further digging it does seem to be running the pattern against the underlying `Date` object. When I use a custom directive that formats the date, however, it runs it against the actual input. The only documentation I see for ng-pattern is a brief mention here under input. Is there anything else that maybe I'm missing?