Regression introduced by new min max validators
See original GitHub issueBug Report
Affected Package
@angular/forms 12+
Is this a regression?
Yes, the previous version in which this bug was not present was: 11
Description
@angular/forms 12 introduced min and max validators based on the min and max attributes presence in #39063.
Before that, the browser would react to min/max attributes by doing validation and also by preventing to introduce invalid value. Both of those native features are now impossible to leverage.
Also, before that, it was possible to deactivate the browser native features with a null value, such as [min]="null"
or [min]="undefined"
. This is now impossible to do in strict mode compilation, because the new directive only accept string | number
and would result in a compilation error. Possible temporary workaround for that is to use $any
casting similar to [min]="configuration.min ?? $any(undefined)"
Suggested fixes
I would suggest that both directives create, and maintain, the equivalent attribute on the HTMLInputElement, so that browsers are able to react accordingly and adapt their UX.
And I would suggest to loosen the input type like so:
- @Input() min!: string|number;
+ @Input() min: string|number|null|undefined;
If those suggestions sound mergeable I could create PRs for it.
Minimal Reproduction
- https://stackblitz.com/edit/min-max-regression-angular-11
- https://stackblitz.com/edit/min-max-regression-angular-12, same as above, but with strict mode disabled, and Angular 12
Exception or Error
Type 'number | null' is not assignable to type 'string | number'.
Your Environment
Angular Version:
Angular CLI: 12.0.1
Node: 14.17.0
Package Manager: yarn 1.22.5
OS: linux x64
Angular: 12.0.1
... animations, cdk, cli, common, compiler, compiler-cli, core
... forms, language-service, localize, material
... platform-browser, platform-browser-dynamic, router
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1200.1
@angular-devkit/build-angular 12.0.1
@angular-devkit/core 12.0.1
@angular-devkit/schematics 12.0.1
@angular/flex-layout 12.0.0-beta.34
@schematics/angular 12.0.1
ng-packagr 12.0.0
rxjs 6.6.7
typescript 4.2.4
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:18 (17 by maintainers)
Top GitHub Comments
As discussed offline the
min
attribute is being removed when the value is 0 is because of thishost
binding:Hi, thanks for reporting the issue.
Just want to provide a bit more context after initial investigation. The
min
/max
validators were modeled afterminlength
/maxlength
ones, which have the input type defined asstring|number
:https://github.com/angular/angular/blob/4ac55ca676769a54a76c5881d40109b556f497b7/packages/forms/src/directives/validators.ts#L553-L554
However in the code below the input value is checked against
null
andundefined
values as well:https://github.com/angular/angular/blob/4ac55ca676769a54a76c5881d40109b556f497b7/packages/forms/src/directives/validators.ts#L569-L571
So the
minlength
andmaxlength
directives would have the same problem from types perspective, but would work as expected (no validation happening) if the value isnull
orundefined
.It looks like the
min
andmax
validators work withnull
andundefined
by accident where these values are converted toNaN
and after that the comparison with a number always givesfalse
, so the underlying minValidator and maxValidator functions return “validation is successful” result.Looking at other validator directives in the packages/forms/src/directives/validators.ts file, some of them have special checks for when validator should be enabled, such as the required validator, but in some cases (for example in the pattern validator), the validation will always happen and there is no way to conditionally enable/disable it.
My conclusion is that we should revisit all existing form validators (not only
min
andmax
) from that perspective and make sure that the logic is consistent. Specifically verify (by adding tests) that there is a way to conditionally disable validation, update input types accordingly (to allow fornull|undefined
types) and mention this behavior in docs.