Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

ngModel parse errors always use named parser #10076

Closed
Narretz opened this issue Nov 16, 2014 · 3 comments · Fixed by #16347 or javascript-indonesias/angular.js#37
Closed

ngModel parse errors always use named parser #10076

Narretz opened this issue Nov 16, 2014 · 3 comments · Fixed by #16347 or javascript-indonesias/angular.js#37

Comments

@Narretz
Copy link
Contributor

Narretz commented Nov 16, 2014

For our core parsers, we use a private / undocumented property called $$parserName, so that the $error is named, e.g. $error.date. Other parsers will always set $error.parse. When you have something like this:

<input type="date" my-parser ng-model="asdf"/>

where myParser adds:

ctrl.$parsers.push(function() {
  return undefined;
});

the $error will nevertheless be date, because the $$parserName is set in the link function, and $$runValidators will always use the $$parserName if it is set.

@Narretz Narretz added this to the Backlog milestone Nov 16, 2014
@Narretz Narretz changed the title ngModel parse errors always use named parser names ngModel parse errors always use named parser Nov 16, 2014
@petebacondarwin
Copy link
Contributor

Is this not a bug for 1.3?

@Narretz
Copy link
Contributor Author

Narretz commented Dec 11, 2014

I think we must break the API to fix it properly, so that's why I moved
it to 1.4.

And I really don't like that we cannot return undefined from a parser
without generating a parse error, so that's another reason to break it.

Am 11.12.2014 um 21:26 schrieb Pete Bacon Darwin:

Is this not a bug for 1.3?


Reply to this email directly or view it on GitHub
#10076 (comment).

@Narretz Narretz self-assigned this Sep 23, 2015
@matthias-ccri
Copy link

matthias-ccri commented Aug 19, 2016

I just ran into this bug when writing a directive for an input[type=number] element. Returning undefined from its parser made the element have an error class of 'ng-invalid-number'. Calling $setValidity() allows me to set an additional error class, but it does not remove 'ng-invalid-number'.

It seems that a single instance of ngModelCtrl is shared between all directives on an element, so changing $$parserName would overwrite Angular's native numberInputType directive, which is not ok.

I don't see a fix for this. Does anyone have a workaround?

Here's my use case:
My directive is meant to support having a unit suffix ("feet") at the end of a number in an input field. The directive inserts a parser function before the numberInputType directive's parser. It takes the viewValue string, removes the "feet" part, and passes the number string to the numberInputType parser. So it should work seamlessly.
But I want to have an error case – if the user types "10 meters", I want to invalidate the field with an error class of 'ng-invalid-units'. So I call $setValidity() and return undefined. But because of this error, I get the 'ng-invalid-number' error class as well.

While I was writing that out, I figured out a solution -- return null instead of undefined. That will indicate "no value", which is acceptable. Or I could use the $validators object to avoid doing it from a parser.

So, hopefully this information might help someone else.

Narretz added a commit to Narretz/angular.js that referenced this issue Nov 27, 2017
This commit changes how input elements use the private $$parserName
property on the ngModelController to name parse errors. Until now,
the input types (number, date etc.) would set $$parserName when
the inputs were initialized, which meant that any other parsers on
the ngModelController would also be named after that type. The
effect of that was that the `$error` property and the `ng-invalid-...`
class would always be that of the built-in parser, even if the custom
parser had nothing to do with it.

The new behavior is that the $$parserName is only set if the actual
parser is invalid, i.e. returns `undefined`.

Also, $$parserName has been removed from input[email] and input[url],
as these types do not have a built-in parser anymore.

BREAKING CHANGE:

Custom parsers that fail to parse on input types email, url, date, month, time,
datetime-local, week, do no longer set $error[inputType], and no longer set the class
`ng-invalid-[inputType]`. Instead, they set $error.parse and `ng-invalid-parse`.

Closes angular#14292
Closes angular#10076
Narretz added a commit to Narretz/angular.js that referenced this issue Dec 1, 2017
This commit changes how input elements use the private $$parserName
property on the ngModelController to name parse errors. Until now,
the input types (number, date etc.) would set $$parserName when
the inputs were initialized, which meant that any other parsers on
the ngModelController would also be named after that type. The
effect of that was that the `$error` property and the `ng-invalid-...`
class would always be that of the built-in parser, even if the custom
parser had nothing to do with it.

The new behavior is that the $$parserName is only set if the built-in
parser is invalid i.e. returns `undefined`.

Also, $$parserName has been removed from input[email] and input[url],
as these types do not have a built-in parser anymore.

BREAKING CHANGE:

*Custom* parsers that fail to parse on input types "email", "url", "number", "date", "month",
"time", "datetime-local", "week", do no longer set `ngModelController.$error[inputType]`, and
the `ng-invalid-[inputType]` class. Also, custom parsers on input type "range" do no
longer set `ngModelController.$error.number` and the `ng-invalid-number` class.

Instead, any custom parsers on these inputs set `ngModelController.$error.parse` and
`ng-invalid-parse`.

Closes angular#14292
Closes angular#10076
Narretz added a commit that referenced this issue Dec 4, 2017
This commit changes how input elements use the private $$parserName
property on the ngModelController to name parse errors. Until now,
the input types (number, date etc.) would set $$parserName when
the inputs were initialized, which meant that any other parsers on
the ngModelController would also be named after that type. The
effect of that was that the `$error` property and the `ng-invalid-...`
class would always be that of the built-in parser, even if the custom
parser had nothing to do with it.

The new behavior is that the $$parserName is only set if the built-in
parser is invalid i.e. returns `undefined`.

Also, $$parserName has been removed from input[email] and input[url],
as these types do not have a built-in parser anymore.

Closes #14292
Closes #10076
Closes #16347

BREAKING CHANGE:

*Custom* parsers that fail to parse on input types "email", "url", "number", "date", "month",
"time", "datetime-local", "week", do no longer set `ngModelController.$error[inputType]`, and
the `ng-invalid-[inputType]` class. Also, custom parsers on input type "range" do no
longer set `ngModelController.$error.number` and the `ng-invalid-number` class.

Instead, any custom parsers on these inputs set `ngModelController.$error.parse` and
`ng-invalid-parse`. This change was made to make distinguishing errors from built-in parsers
and custom parsers easier.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.