-
Notifications
You must be signed in to change notification settings - Fork 27.4k
ng-pattern binding is not working in v1.4 #12344
Comments
It doesn't actually have to do with @aquisio: the @team (especially forms people): There seems to be a need for custom handling of |
hm. ngPattern should probably only try to match the viewValue, not the modelValue. Because that's what pattern does. |
Thinking about it again, you can't convert a regex to a date for comparing with the So, for the date input it does make sense for |
Set patternDirective validator to test against viewValue instead of modelValue. Closes angular#12344, angular#12618
Since the HTML5 pattern validation constraint validates the input value, we should also validate against the viewValue. This allows e.g. input[date] to validate both the input format of the date and the date object itself. Fixes angular#12344
Since the HTML5 pattern validation constraint validates the input value, we should also validate against the viewValue. This allows e.g. input[date] to validate both the input format of the date and the date object itself. Fixes angular#12344
Since the HTML5 pattern validation constraint validates the input value, we should also validate against the viewValue. This allows e.g. input[date] to validate both the input format of the date and the date object itself. Fixes angular#12344
Since the HTML5 pattern validation constraint validates the input value, we should also validate against the viewValue. This allows e.g. input[date] to validate both the input format of the date and the date object itself. Until Angular 1.3, the validated value was Fixes angular#12344 BREAKING CHANGE: `ngPattern` and `pattern` directives will validate the regex against the `viewValue` of `ngModel`, i.e. the value of the model before the $parsers are applied. Previously, the modelValue (the result of the $parsers) was validated. This fixes issues where `input[date]` and `input[number]` could not be validated because the viewValue string had been parsed into `Date`/`Number` respectively. This change also brings the directives in line with HTML5 constraint validation, which validates against the value of the input. The change is unlikely to cause applications to fail, because even before Angular 1.3, the value that was validated by pattern could have been manipulated by the $parsers array, as all validation was done inside this pipeline. If you rely on the pattern being validated against the modelValue, you must create your own validator directive that overwrites the built-in pattern validator: ``` .directive('patternModelOverwrite', function patternModelOverwriteDirective() { return { restrict: 'A', require: '?ngModel', priority: 1, compile: function() { var regexp, patternExp; return { pre: function(scope, elm, attr, ctrl) { if (!ctrl) return; attr.$observe('pattern', function(regex) { //The built-in directive will call our overwritten validator (see below). //We just need to update the regex. The preLink fn guaranetees our observer //is called first if (isString(regex) && regex.length > 0) { regex = new RegExp('^' + regex + '$'); } if (regex && !regex.test) { //The built-in validator will throw at this point return; } regexp = regex || undefined; }); }, post: function(scope, elm, attr, ctrl) { if (!ctrl) return; regexp, patternExp = attr.ngPattern || attr.pattern; //The postLink fn guarantees we overwrite the built-in pattern validator ctrl.$validators.pattern = function(value) { return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value); }; } }; } }; }); ```
Since the HTML5 pattern validation constraint validates the input value, we should also validate against the viewValue. This allows e.g. input[date] to validate both the input format of the date and the date object itself. Fixes angular#12344 BREAKING CHANGE: `ngPattern` and `pattern` directives will validate the regex against the `viewValue` of `ngModel`, i.e. the value of the model before the $parsers are applied. Previously, the modelValue (the result of the $parsers) was validated. This fixes issues where `input[date]` and `input[number]` could not be validated because the viewValue string had been parsed into `Date`/`Number` respectively. This change also brings the directives in line with HTML5 constraint validation, which validates against the value of the input. The change is unlikely to cause applications to fail, because even before Angular 1.3, the value that was validated by pattern could have been manipulated by the $parsers array, as all validation was done inside this pipeline. If you rely on the pattern being validated against the modelValue, you must create your own validator directive that overwrites the built-in pattern validator: ``` .directive('patternModelOverwrite', function patternModelOverwriteDirective() { return { restrict: 'A', require: '?ngModel', priority: 1, compile: function() { var regexp, patternExp; return { pre: function(scope, elm, attr, ctrl) { if (!ctrl) return; attr.$observe('pattern', function(regex) { //The built-in directive will call our overwritten validator (see below). //We just need to update the regex. The preLink fn guaranetees our observer //is called first if (isString(regex) && regex.length > 0) { regex = new RegExp('^' + regex + '$'); } if (regex && !regex.test) { //The built-in validator will throw at this point return; } regexp = regex || undefined; }); }, post: function(scope, elm, attr, ctrl) { if (!ctrl) return; regexp, patternExp = attr.ngPattern || attr.pattern; //The postLink fn guarantees we overwrite the built-in pattern validator ctrl.$validators.pattern = function(value) { return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value); }; } }; } }; }); ```
Since the HTML5 pattern validation constraint validates the input value, we should also validate against the viewValue. While this worked in core up to Angular 1.2, in 1.3, we changed not only validation, but the way `input[date]` and `input[number]` are handled - they parse their input values into `Date` and `Number` respectively, which cannot be validated by a regex. Fixes angular#12344 BREAKING CHANGE: The `ngPattern` and `pattern` directives will validate the regex against the `viewValue` of `ngModel`, i.e. the value of the model before the $parsers are applied. Previously, the modelValue (the result of the $parsers) was validated. This fixes issues where `input[date]` and `input[number]` cannot be validated because the viewValue string is parsed into `Date` and `Number` respectively (starting with Angular 1.3). It also brings the directives in line with HTML5 constraint validation, which validates against the input value. This change is unlikely to cause applications to fail, because even in Angular 1.2, the value that was validated by pattern could have been manipulated by the $parsers, as all validation was done inside this pipeline. If you rely on the pattern being validated against the modelValue, you must create your own validator directive that overwrites the built-in pattern validator: ``` .directive('patternModelOverwrite', function patternModelOverwriteDirective() { return { restrict: 'A', require: '?ngModel', priority: 1, compile: function() { var regexp, patternExp; return { pre: function(scope, elm, attr, ctrl) { if (!ctrl) return; attr.$observe('pattern', function(regex) { //The built-in directive will call our overwritten validator (see below). //We just need to update the regex. The preLink fn guaranetees our observer //is called first if (isString(regex) && regex.length > 0) { regex = new RegExp('^' + regex + '$'); } if (regex && !regex.test) { //The built-in validator will throw at this point return; } regexp = regex || undefined; }); }, post: function(scope, elm, attr, ctrl) { if (!ctrl) return; regexp, patternExp = attr.ngPattern || attr.pattern; //The postLink fn guarantees we overwrite the built-in pattern validator ctrl.$validators.pattern = function(value) { return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value); }; } }; } }; }); ```
Since the HTML5 pattern validation constraint validates the input value, we should also validate against the viewValue. While this worked in core up to Angular 1.2, in 1.3, we changed not only validation, but the way `input[date]` and `input[number]` are handled - they parse their input values into `Date` and `Number` respectively, which cannot be validated by a regex. Fixes angular#12344 BREAKING CHANGE: The `ngPattern` and `pattern` directives will validate the regex against the `viewValue` of `ngModel`, i.e. the value of the model before the $parsers are applied. Previously, the modelValue (the result of the $parsers) was validated. This fixes issues where `input[date]` and `input[number]` cannot be validated because the viewValue string is parsed into `Date` and `Number` respectively (starting with Angular 1.3). It also brings the directives in line with HTML5 constraint validation, which validates against the input value. This change is unlikely to cause applications to fail, because even in Angular 1.2, the value that was validated by pattern could have been manipulated by the $parsers, as all validation was done inside this pipeline. If you rely on the pattern being validated against the modelValue, you must create your own validator directive that overwrites the built-in pattern validator: ``` .directive('patternModelOverwrite', function patternModelOverwriteDirective() { return { restrict: 'A', require: '?ngModel', priority: 1, compile: function() { var regexp, patternExp; return { pre: function(scope, elm, attr, ctrl) { if (!ctrl) return; attr.$observe('pattern', function(regex) { /** * The built-in directive will call our overwritten validator * (see below). We just need to update the regex. * The preLink fn guaranetees our observer is called first. */ if (isString(regex) && regex.length > 0) { regex = new RegExp('^' + regex + '$'); } if (regex && !regex.test) { //The built-in validator will throw at this point return; } regexp = regex || undefined; }); }, post: function(scope, elm, attr, ctrl) { if (!ctrl) return; regexp, patternExp = attr.ngPattern || attr.pattern; //The postLink fn guarantees we overwrite the built-in pattern validator ctrl.$validators.pattern = function(value) { return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value); }; } }; } }; }); ```
Since the HTML5 pattern validation constraint validates the input value, we should also validate against the viewValue. While this worked in core up to Angular 1.2, in 1.3, we changed not only validation, but the way `input[date]` and `input[number]` are handled - they parse their input values into `Date` and `Number` respectively, which cannot be validated by a regex. Fixes #12344 BREAKING CHANGE: The `ngPattern` and `pattern` directives will validate the regex against the `viewValue` of `ngModel`, i.e. the value of the model before the $parsers are applied. Previously, the modelValue (the result of the $parsers) was validated. This fixes issues where `input[date]` and `input[number]` cannot be validated because the viewValue string is parsed into `Date` and `Number` respectively (starting with Angular 1.3). It also brings the directives in line with HTML5 constraint validation, which validates against the input value. This change is unlikely to cause applications to fail, because even in Angular 1.2, the value that was validated by pattern could have been manipulated by the $parsers, as all validation was done inside this pipeline. If you rely on the pattern being validated against the modelValue, you must create your own validator directive that overwrites the built-in pattern validator: ``` .directive('patternModelOverwrite', function patternModelOverwriteDirective() { return { restrict: 'A', require: '?ngModel', priority: 1, compile: function() { var regexp, patternExp; return { pre: function(scope, elm, attr, ctrl) { if (!ctrl) return; attr.$observe('pattern', function(regex) { /** * The built-in directive will call our overwritten validator * (see below). We just need to update the regex. * The preLink fn guaranetees our observer is called first. */ if (isString(regex) && regex.length > 0) { regex = new RegExp('^' + regex + '$'); } if (regex && !regex.test) { //The built-in validator will throw at this point return; } regexp = regex || undefined; }); }, post: function(scope, elm, attr, ctrl) { if (!ctrl) return; regexp, patternExp = attr.ngPattern || attr.pattern; //The postLink fn guarantees we overwrite the built-in pattern validator ctrl.$validators.pattern = function(value) { return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value); }; } }; } }; }); ```
I think this was a stupid decision to make. It completely brakes the idea of ngModel's Imagine I have a I might want to apply a And you broke that! And you added some questionable reasoning like HTML5 pattern constraint validates the input value, so we validate the viewValue. What? If i wanted native html5 validation I wouldn't add That's why we add the We could look at the problem from another angle. |
@everdimension, there are two different subjects touched here:
Regarding (1), while it is true that no solution is perfect (i.e. not everyone will be happy with any one solution), we picked the one that would be useful in most usecases. Now that Angular supports several types of inputs (e.g. number, date, time etc), it's not uncommon for the Of course, the usecase you describe is still valid and you can support it via a custom validator. I understand this is more work than just using a built-in validator, but it's still pretty trivial and the usecase is not very common. Regarding (2), indeed one could have gone the other way around - both approaches have pros and cons. At this point though, I believe that, altering the current behavior, would be too much of a breaking change to justify the benefit. Also, note that |
This would be appropriate solution if all I wanted was to validate a field using a regex pattern. But like I said, there is a place where I use So basically my solution would be to overwrite the existing pattern directive, which is a kind of dirty solution. Yes, there are two different issues, and in my opinion both of them are done wrong. The (1) breaks the native angular pipeline, killing an important part of the framework. Date, number inputs? Handle them like a special case! They are a special case anyway, in my opinion. The (2) interferes with expected behavior. Although this one is more understandable as there are several places where angular creates directives for native html attributes. This is kind of how angular is built. But still I never expected |
@everdimension I don't think it was ever intended that using the HTML5 validation attributes keeps Angular from adding validation rules based on them. Even going back to 1.3, the docs state clearly that using the |
You can do something simple, such as apply the Regarding (2), whether it was a good or bad decision is a different discussion, but at this point changing it doesn't justify the breaking change, so it might be a pointless discussion 😉 |
why isn't it documented in the migration guide the ng-pattern directive code changed from 1.3.16
to 1.4.14
|
For future reference: #15765 |
I understand that v1.3 introduced some changes in the recommended usage of ng-pattern when the validation pattern / RegExp is exposed as a model property. This change is documented in the migration notes and works correctly in v1.3, as demonstrated in this JSFiddle.
However, using the same implementation in v1.4 does not work, as this JSFiddle shows. Instead, pattern validation always fails.
The text was updated successfully, but these errors were encountered: