angular: Regression introduced by new min max validators

Bug 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)"

image

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

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

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 18 (17 by maintainers)

Commits related to this issue

Most upvoted comments

As discussed offline the min attribute is being removed when the value is 0 is because of this host binding:

@Directive({
  selector:
      'input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]',
  providers: [MIN_VALIDATOR],
  host: {'[attr.min]': 'min ? min : null'}
})

Hi, thanks for reporting the issue.

Just want to provide a bit more context after initial investigation. The min/max validators were modeled after minlength/maxlength ones, which have the input type defined as string|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 and undefined values as well:

https://github.com/angular/angular/blob/4ac55ca676769a54a76c5881d40109b556f497b7/packages/forms/src/directives/validators.ts#L569-L571

So the minlength and maxlength directives would have the same problem from types perspective, but would work as expected (no validation happening) if the value is null or undefined.

It looks like the min and max validators work with null and undefined by accident where these values are converted to NaN and after that the comparison with a number always gives false, 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 and max) 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 for null|undefined types) and mention this behavior in docs.

thanks @PowerKiKi this helped.

I would think you can workaround this issue by binding to [attr.min] instead, fwiw.