AngularJS number input formatted view
You need to add the step
attribute to your number
input.
<input type="number" step="0.01" />
This will allow floating points.
http://jsfiddle.net/LCZfd/1/
Also, I'd recommend reviewing the bug thread on number
inputs in Firefox. You may want to consider not using this input type, as it was just finally supported in this release of FF.
- https://bugzilla.mozilla.org/show_bug.cgi?id=344616
- http://caniuse.com/input-number
All these years later, there still isn't an HTML5 solution out of the box for this.
I am using <input type="tel">
or <input type="text">
("tel" brings up a numeric keyboard in Android and iOS, which in some cases is a bonus.)
Then I needed a directive to:
- filter out non-numeric characters
- add thousand-separator commas as the user types
- use
$parsers
andkeyup
to setelem.val()
and$formatters
to set the display... - ...while behind the scenes, assign
ng-model
a floating point number
The directive example below does this, and it accepts negatives and floating point numbers unless you specify you want only positive or integers.
It's not the full solution I would like, but I think it bridges the gap.
HTML
<input type="text" ng-model="someNumber" number-input />
JAVASCRIPT
myApp.directive('numberInput', function($filter) {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.push(function(modelValue) {
return setDisplayNumber(modelValue, true);
});
// it's best to change the displayed text using elem.val() rather than
// ngModelCtrl.$setViewValue because the latter will re-trigger the parser
// and not necessarily in the correct order with the changed value last.
// see http://radify.io/blog/understanding-ngmodelcontroller-by-example-part-1/
// for an explanation of how ngModelCtrl works.
ngModelCtrl.$parsers.push(function(viewValue) {
setDisplayNumber(viewValue);
return setModelNumber(viewValue);
});
// occasionally the parser chain doesn't run (when the user repeatedly
// types the same non-numeric character)
// for these cases, clean up again half a second later using "keyup"
// (the parser runs much sooner than keyup, so it's better UX to also do it within parser
// to give the feeling that the comma is added as they type)
elem.bind('keyup focus', function() {
setDisplayNumber(elem.val());
});
function setDisplayNumber(val, formatter) {
var valStr, displayValue;
if (typeof val === 'undefined') {
return 0;
}
valStr = val.toString();
displayValue = valStr.replace(/,/g, '').replace(/[A-Za-z]/g, '');
displayValue = parseFloat(displayValue);
displayValue = (!isNaN(displayValue)) ? displayValue.toString() : '';
// handle leading character -/0
if (valStr.length === 1 && valStr[0] === '-') {
displayValue = valStr[0];
} else if (valStr.length === 1 && valStr[0] === '0') {
displayValue = '';
} else {
displayValue = $filter('number')(displayValue);
}
// handle decimal
if (!attrs.integer) {
if (displayValue.indexOf('.') === -1) {
if (valStr.slice(-1) === '.') {
displayValue += '.';
} else if (valStr.slice(-2) === '.0') {
displayValue += '.0';
} else if (valStr.slice(-3) === '.00') {
displayValue += '.00';
}
} // handle last character 0 after decimal and another number
else {
if (valStr.slice(-1) === '0') {
displayValue += '0';
}
}
}
if (attrs.positive && displayValue[0] === '-') {
displayValue = displayValue.substring(1);
}
if (typeof formatter !== 'undefined') {
return (displayValue === '') ? 0 : displayValue;
} else {
elem.val((displayValue === '0') ? '' : displayValue);
}
}
function setModelNumber(val) {
var modelNum = val.toString().replace(/,/g, '').replace(/[A-Za-z]/g, '');
modelNum = parseFloat(modelNum);
modelNum = (!isNaN(modelNum)) ? modelNum : 0;
if (modelNum.toString().indexOf('.') !== -1) {
modelNum = Math.round((modelNum + 0.00001) * 100) / 100;
}
if (attrs.positive) {
modelNum = Math.abs(modelNum);
}
return modelNum;
}
}
};
});
https://jsfiddle.net/benlk/4dto9738/
As written in the comments, input type="number"
doesn't support anything but digits, a decimal separator (usually ,
or .
depending on the locale) and -
or e
. You may still enter whatever you want, but the browser will discard any unknown / incorrect character.
This leaves you with 2 options:
- Use
type="text"
and pattern validation likepattern="[0-9]+([\.,][0-9]+)*"
to limit what the user may enter while automatically formatting the value as you do in your example. - Put an overlay on top of the input field that renders the numbers how you want and still allows the user to use the custom
type="number"
input controls, like demonstrated here.
The latter solution uses an additional <label>
tag that contains the current value and is hidden via CSS when you focus the input field.
You cannot use values with ,
because type=number
only takes numbers, adding a comma makes it a string.
See http://jsfiddle.net/LCZfd/5
You're better off making your own controls if you want commas. One with a true value (the number) and a display value (the string).