Angular.js: <input type="number" max="{{max}}"> does not set $error.max property

Created on 14 Apr 2013  路  46Comments  路  Source: angular/angular.js

When using an input of type number, with the max (or min) attribute set from the model, then the max field is not set in the error object of the input. This is due to the fact that in method "numberInputType", the value of attr.max is undefined. It is (probably) set from the model only later.

Checking the HTML, shows that the max attribute gets the correct value, set from the model.

In summary, the following does not work as expected:
input type="number" max="{{max}}"
The $error for this input field does not contain a boolean value named "max".

Here is a demo : http://plnkr.co/edit/YiExG5GpFt5MKKXoO4GE

forms moderate confusing bug

Most helpful comment

For for old Angular versions use fallback values before model is initialized:
max="{{max || 99999}}"
It worked for me.

All 46 comments

this is possibly related to issue #2144 - there clearly are some issue with cross-browser input type=number.. :(

I think the parseFloat line should be moved inside the maxValidator function. The interp seems like it's already being done beforehand, but the validator is trying to be 'smart' and pre-compute it. I've tried it and it seems to work well (in chrome)

Will require further testing and unit tests, but this fixed it for me:
https://github.com/jamie-pate/angular.js/compare/scwp

This appears to be solved in the latest angular 1.2.3

Problem still occurring in v1.2.7.

The documentation may indicate that it's expecting a string, but it does go against expectation as this complicates things if you want all properties to be databound and not something mid-term.
Silly thing is that the spinner still limits min/max properly according to the {{expression}}, and the browser also validates the form correctly on submission if "novalidate" isn't present.
The missing bit, really, is $error.min/max not updating.

I can't repro this with 1.2.7: http://plnkr.co/edit/4HU4jdG1ljrnoXYuegQo?p=preview

it appears to work correctly. can you please post expected vs actual result and any other instructions needed to repro the bug.

Hi Igor,

Thanks for having a look at this!
I can see everything works fine in your Plunkr and can't get it to break, so I don't know why on my case it doesn't work. The only thing I'm realising is that, on the generated HTML for my input element, angular isn't adding the ng-valid-min and ng-valid-max classes as in your Plunkr.

An adapted version of yours generated (works):

<input type="number" name="P4" min="0" max="100" ng-model="container.P4.quantity" 
class="ng-pristine ng-valid ng-valid-number ng-valid-max ng-valid-min">

My generated HTML (doesn't work):

<input type="number" name="P4" min="0" max="100" ng-model="container.P4.Value" 
class="ng-pristine ng-valid ng-valid-number">

Resulting in:

myform.P4.$error = {"number":false}
myform.P4.$error.min =
myform.P4.$error.max =

I can't reproduce my problem in the Plunkr, so I'm at a loss.
Any ideas on what I might be doing wrong?

We are having this issue with 1.2.13
Here is a fiddle showing the issue. Please use chrome to test:
http://jsfiddle.net/sberube/BnE73/

Steps:

  1. For enter a number, type in 115
    1a. Observe that value.$error.max goes to true meaning the # has failed MAX validation
  2. Change the dropdown to Unlimited, this should set {{max}} to 500 where before it was 100
    2a. Observe that the $error still shows a max error when the number is now in the valid range.
  3. Type 116 in the input field
    3a. observe that $error.max goes to false

So the {{max}} interpolation is not re-validating the input, but changing the input causes re-validation including the new value. This is the bug we are experiencing with 1.2.13

EDIT:
We are going to see if this solves our issue until angular natively supports this:
http://jsfiddle.net/g/s5gKC/

Caitlin;
According to the documentation it does:
http://docs.angularjs.org/api/ng/input/input%5Bnumber%5D

On Wed, Feb 19, 2014 at 11:03 AM, Caitlin Potter
[email protected]:

I'm not sure what you were expecting, angular doesn't support the maxattribute

Reply to this email directly or view it on GitHubhttps://github.com/angular/angular.js/issues/2404#issuecomment-35514255
.

The issue appears on this case http://plnkr.co/edit/4CPpJl when min and max value are dynamically set.

I think the solution to this is the novalidate attribute - Well, solved it for me anyway.

I am currently having a related issue. In my case, when the numberInputType controller is instantiated, attr.min and/or attr.max evaluate as falsy. The solution is to replace if (attr.max) with if ('max' in attr) and if (attr.min) with if ('min' in attr)

Unfortunately my employer thus far has not approved (and looks like it won't any time soon) the CLA so someone else will have to make this PR.

PS: also needs a check for NaN since attr.max could be anything during validation now.

Still present in 1.2.18

@gkocjan can you provide an example? this seems to have been fixed back in 1.1.3, based on a quick bisect of releases --- http://plnkr.co/edit/7KNcOK7CVSjWDUt9JHbN?p=preview (works in 1.1.3, fails in 1.1.2), probably was originally fixed by bb8448c011127306df08c7479b66e5afe7a0fa94 (It's also working in 1.2.0, 1.2.18, 1.2.17, snapshot, 1.3-beta.1, ...)

@petebacondarwin we could probably close this issue if this was fixed by that CL

@caitp here is example: http://plnkr.co/edit/vLq79q4tZJn4PHDbN73i?p=preview
I notice that simple example, when every variable is created in controller, works (first input in example). Problem is, when variable is created by directive, in my case it was pagination from bootstrap-ui (second input in example). If type number greater than max input is still valid.

In second example after adding variable in controller it also starts to work. Just uncomment
//$scope.numPagesFromPagination = 0; in controller.

@gkocjan http://plnkr.co/edit/Vy6OYQH18FcjqEnOoVT9?p=preview

(setting the page to page 10 will invalidate the model)

(Also, the pagination directive doesn't use ng-model and instead depends on page, an isolate scope property)

I can confirm this. If I set $scope.amount=5in controller, then max="{{amount}}" works as expected but when I set the amount some other way (e.g. from scope), angular seems to ignore the max attribute completely whereas the browser sees it.

if you can reproduce that, you need to show your issue, because as far as anyone can tell this is working. Can you make a demo, @lhahne?

This was a concurrency issue at least for me. If max is null in the beginning and later gets updated, the browser will pick this up but angular will not.

Can you make a demo, @lhahne?

This means an actual reproduction using a recent release or snapshot build, so that we can determine if this is a bug to be fixed.

Here you go http://plnkr.co/edit/EuuRHb9vUVw4ODhmsfjq?p=preview The first checkbox checks for max, the second does not. Not sure if this is actually even supposed to work in this case.

@lhahne I see, that's a fairly trivial fix.

The issue is the way we're testing if we need to register a min/max validator or not: https://github.com/angular/angular.js/blob/master/src/ng/directive/input.js#L1083

      if(attr.max) {

This evaluates to the empty string because the property is not set in scope yet, though the attribute is provided.

This is trivial to fix if you'd like to submit a pull request. If not I'll patch that later today

@caitp I think you even had a pull request with that fix back when max/min was still on $parsers: https://github.com/angular/angular.js/pull/6002

Here's an issue that would be closed by this fix: https://github.com/angular/angular.js/pull/6369#issuecomment-42793445

nah, that PR was for a different issue, but this one is similarly trivial

I was trying to fix this but I can't seem to get this to fail in unit tests. This is what I tried and I do not understand why it does not fail even though it is completely analogous to my previous example of the problem.

  it('should validate even if max value changes on-the-fly and is null in the beginning', function(done) {
    scope.max = null;
    compileInput('<input type="number" ng-model="value" name="alias" max="{{max}}" />');
    scope.max = 10;
    scope.$digest();

    changeInputValueTo('5');
    expect(inputElm).toBeValid();

    scope.max = 0;
    scope.$digest(function () {
      expect(inputElm).toBeInvalid();
      done();
    });
  });

Looking at the number validator, there are two problems here:
a) First, it doesn't set up the max/min validators if they are initially falsey
b) It doesn't fire validation when max/min change later

Theoretically, the number validations should be added to the $validators collection, but since number also uses formatters, and there is currently some discussion about the whole inout processing, it's probably best to defer this.

@lhahne Your test doesn't work, because when max is undefined or null before compilation, no max validator is set. When you change max afterwards, it doesn't fail because the max validator is not set, and even if it was, it would still fail because the directive doesn't listen to max={{value}} changes.

@lhahne I had actually said that this should be a simple patch to write, but it turns out I was mistaken!

This is probably not too bad for the 1.2 branch, but for 1.3 it's a bit more complicated than it needs to be. However, we might be able to fix this up after all anyways, so at least there's that.

Do you have any timetable on fixing this and the other which happens once you update the max value later?

:+1:

This is still unfixed right? Or does Angular _by design_ only handle the max attribute as a fixed value?

Here's a simple example of the bug in Angular 1.2.22: http://plnkr.co/edit/lNemYyFrHF9gyRgY8KIT?p=preview

Same problem with input type='date' min max for 1.3.0-beta.19.
Plunkr modified from @lhahne 's

http://plnkr.co/edit/HOIsjV?p=preview

@matsko is this something we can address in RCs?

I have a PR that fixes this for date. The same logic applies here. And no it won't cause any breaking changes so we're safe to patch during RC.

This is working on the current master, but if the min or max value is changed then the input field doesn't reconsider itself. This PR fixes the issue for input[type="number"]: https://github.com/angular/angular.js/pull/8913

Still experiencing this issue on v1.3.10... http://plnkr.co/edit/uS4zsh05jeP7pF7A2aVk

Using an initialisation value that isn't null or "" resolves the issue for me e.g. $scope.max = "1"

@adrianduke try

ng-max='{{max}}'

http://plnkr.co/edit/DF4R6vfQpf909jj19sFv?p=preview

BTW, this seems to have been fixed in 1.3.14 (plnkr) and 1.4.0-beta.5 (plnkr).

It would have expected this commit to fix it - https://github.com/angular/angular.js/commit/b3502835039178296b730b7526e5666b66ba9156
But this was already there at 1.3.0

@petebacondarwin WIll it be released in upcoming 1.3.16 release?

@piotrkulpinski - this was already there in 1.3.14 and so will continue to appear in the next release too.

+1 here 1.4.x

Hi guys, in the documentation is missing the attr ng-max and ng-min for input type number.

Interesting! They are not documented as standalone directives either...
@favio41, would you like to submit a PR ?

just use ng-min and ng-max
It solved all my problems!

For for old Angular versions use fallback values before model is initialized:
max="{{max || 99999}}"
It worked for me.

Was this page helpful?
0 / 5 - 0 ratings