-
Notifications
You must be signed in to change notification settings - Fork 27.4k
option to autocast strings as numbers #11464
Comments
I'll think it's worth reconsidering this. Here's some thoughts:
|
That's why I said to make it an option. It may not be right to turn this on for everybody, but it's certainly good for people that explicitly want that behavior. Could you link to an example of how to build a custom formatter? I've never heard of such a thing. Unless you mean a custom filter? If that's what you mean I can't apply the filter to the field because I've attached the model directly to the input field, so I can't do {{some_value | number}}. Please show me the error of my ways. |
After a few hours of searching and reading, I finally figured out what an angular formatter is and how to apply it to this situation. For people seeing this going forward, I applied @Narretz advice and came up with this: |
Hey @rizen if you want to give a PR a shot that allows non-Number numbers, that'd be great. Here's a list of things that'd be needed:
|
I am also in favour of this, due to the following use case: I am calculating some numbers that I need to put in the model. However, these numbers are currency values, and as such I would like to have them formatted as such, e.g. with 2 decimal spaces, even if the value is A user can input Currently, this is not possible, because if I run the value through the So I have no way of pre-populating the number field with valid numbers at this stage, other than changing the input field to a text type, which of course is not ideal. Ideally, input[number] would in fact accept strings when they come from the model and display them as they are, if they are a valid number. Edit: I might actually create a new issue for this, as this issue is more than 2 years old now. |
As already discussed, a formatter is the way to go. Formatters essentially provide a way for developers to implement their own "switches" to turn features on, either on specific inputs (e.g. with a custom selector that you have to explicitly apply to the inputs) or for all input of a type (e.g. using Finally, as a very last resort, it is even possible to remove or replace the built-in formatters. Additionally, in latest versions it is even possible (even if not well documented) to get hold of the Personally, I would close this as won't fix, because what you want it already possible (without any changes to core), can be applied granularly and there is no intention (afaict) to change the default behavior atm (as this would be a breaking change of something that is useful in most cases). I'll leave the final call to @Narretz 😃 |
I don't think I agree. See the discussion in #16080 and this Plunkr: https://plnkr.co/edit/8XhP9xLhgNgx6RdAz9ZJ?p=preview The
This sets the proper value for that input to So Angular's behaviour actually limits us in this case, preventing us from fully utilizing the native capabilities of the The simplest way to fix this in Angular core would be to mimic the native behaviour, and instead of just type checking if a Do you happen to know if Angular 2 has the same behaviour? Because I would argue that if this is something worth fixing in Angular 2, then Angular 1 should eventually be brought in line as well, as is being done with many other aspects. |
Looking at the source code, there already is a regex in place to check for valid numbers: https://github.com/angular/angular.js/blob/master/src/ng/directive/input.js#L28 All that would realistically need to change imo, is these lines: https://github.com/angular/angular.js/blob/master/src/ng/directive/input.js#L1519-L1521 Replace the |
I have tested this in our own project by creating a custom directive and it seems to work as expected; /**
* Module definition and dependencies
*/
angular.module('Shared.Input.Directive', [])
/**
* Directive
*/
.directive('input', function() {
return {
require: [
'?ngModel',
],
link(scope, element, attrs, ngModel) {
//Array?
if (angular.isArray(ngModel)) {
ngModel = ngModel[0];
}
//Number regex
const NUMBER_REGEXP = /^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
/**
* Helper to apply number handling
*/
function applyNumberHandling() {
//Remove existing formatter
ngModel.$formatters.pop();
//Roll our own
ngModel.$formatters.push(function(value) {
if (!ngModel.$isEmpty(value)) {
if (!NUMBER_REGEXP.test(value)) {
throw Error('Expected `' + value + '` to be a number');
}
value = value.toString();
}
return value;
});
}
//Apply better number validation
if (ngModel && attrs.type === 'number') {
applyNumberHandling();
}
},
};
}); This basically removes the existing formatter and replaces it with the one I proposed in the previous post, using Angular's own internal NUMBER_REGEXP for consistency. |
@adamreisnz I had a chat offline with @gkalpak and it makes perfectly (or atleast some) sense as, in AngularJS, we have a seperation of ViewValue and ModelValue. When working with an API that expects a number, we want to ensure the modelValue is a number type (not a numeric value) hence there's no need to pass in a string. We could argue that we could pass in '2.50' and parse it to a number before doing numerical operations, but we'll again lose the trailing If you have the need to visualize the value differently from the model (visualize it as a string, while the model is a number) you can make use of an simple formatter like so: http://plnkr.co/edit/NJSUppF28ZPKsrWisXZF?p=preview Even tho I understand your point (and I find it odd to have different behavior compared to the way native JS handles it aswell), I also understand @gkalpak's point of view with regards to api usage. |
Ok, thanks for looking into it and for posting your suggestion, it's also a good approach. Not sure if it would be more complex, as the regex is already there, and all I did was basically replace the |
It seems we have come to some sort of consensus 😃 The question is not whether we can implement this (we obviously can 😃), but whether this is the right thing to do (imo it is not 😃). What the browser does (i.e. accepting any string that is a valid representation of a number as In AngularJS, there is a clear separation between the model (actual data) and the view (the visual representation of that data). Using formatters for their intended purpose (i.e. formatting the model data for visual representation in the view) is not a hack or work around. It is normal and common practice (in fact AngularJS itself uses these APIs under the hood for all supported input types). Now, specifically regarding the number input type, there is a contract in AngularJS that the model data bound to such an input is a number (which makes perfect sense imo, since the input is supposed to offer an interface for interacting with numbers). This guarantee allows AngularJS, 3rd-party libraries and app developers to operate on a common assumption that will always hold true: The model value (if not empty) will be of type Changing this, would leave us in a position were we can't be sure of the type of the model data. This would affect several Furthermore, allowing this, would create another inconsistency which makes In a nutshell, by implementing the requested change (and hiding it behind a flag in order to avoid a breaking change) we would be breaking some contracts that make These are obvious downsides. What would we gain in exchange? AFAICT, the only tangible upside is being able to display a value in a specific format. But (as discussed earlier) this is exactly what formatters are for. In addition, using formatters has the following advantages:
Even if the And given how easy it is to re-use logic across AngularJS apps, I really see no reason for not solving this via formatters 😁 |
Ok let's close this issue then 👍 |
There needs to be a way to cast strings as numbers from the model. Angular is used in all sorts of systems where you don't have access to the backend that generates the JSON that populates a field. So if I set a field like this:
<input type="number" ng-model="some_value">
Then angular should trust me when I say that some_value is a number, and run Number() on it.
I know you guys have considered this before, as you did in this ticket: #6683
And I know you've rejected the premise. However, that's just a terrible way to do things. We need a way to at least optionally change a config setting to change this behavior. If you don't, I'm forced to either set the field as "text", which is semantically wrong, or I'm force to loop over all the results as they come in and manually run Number() on them, which adds a lot of code for something that should be automatic. Please reconsider.
The text was updated successfully, but these errors were encountered: