AngularJS - Smart Float Directive
Recently I started looking for an AngluarJS directive to validate numbers and I found the "smart-float" directive here, in the AngularJS documentation. This amazing example solves the problem of convert my numbers that use a comma as decimal mark to a Javascript number.
My problem is that this directive doesn't solve my two problems:
- Display numbers with 2 fractional digits by default.
- Validate numbers with thousands separator.
So, this is an improved directive based on Angular's smart-float directive. First, add the following directive to your application:
myApp.directive("smartFloat", function ($filter) {
var FLOAT_REGEXP_1 = /^\$?\d+.(\d{3})*(\,\d*)$/; //Numbers like: 1.123,56
var FLOAT_REGEXP_2 = /^\$?\d+,(\d{3})*(\.\d*)$/; //Numbers like: 1,123.56
var FLOAT_REGEXP_3 = /^\$?\d+(\.\d*)?$/; //Numbers like: 1123.56
var FLOAT_REGEXP_4 = /^\$?\d+(\,\d*)?$/; //Numbers like: 1123,56
return {
require: "ngModel",
link: function (scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function (viewValue) {
if (FLOAT_REGEXP_1.test(viewValue)) {
ctrl.$setValidity("float", true);
return parseFloat(viewValue.replace(".", "").replace(",", "."));
} else if (FLOAT_REGEXP_2.test(viewValue)) {
ctrl.$setValidity("float", true);
return parseFloat(viewValue.replace(",", ""));
} else if (FLOAT_REGEXP_3.test(viewValue)) {
ctrl.$setValidity("float", true);
return parseFloat(viewValue);
} else if (FLOAT_REGEXP_4.test(viewValue)) {
ctrl.$setValidity("float", true);
return parseFloat(viewValue.replace(",", "."));
} else {
ctrl.$setValidity("float", false);
return undefined;
}
});
ctrl.$formatters.unshift(function (modelValue) {
return $filter("number")(parseFloat(modelValue), 2);
});
},
};
});
Now, add the smart-float directive to your input:
<input
type="text"
id="inputAmount"
name="inputAmount"
placeholder="Amount"
ng-model="amount"
smart-float
/>
This gives you what you need. Now, you can improve it showing to your users that the value in the input is invalid. In the following example I used Bootstrap to demonstrate it:
<form name="myForm" class="form-horizontal" role="form" novalidate>
<div class="form-group" ng-class="{'has-error': myForm.inputAmount.$invalid}">
<label for="inputText3" class="col-sm-2 control-label">Amount</label>
<div class="col-sm-10">
<input
type="text"
class="form-control"
id="inputAmount"
name="inputAmount"
placeholder="Amount"
ng-model="amount"
smart-float
/>
<span class="help-block" ng-show="myForm.inputAmount.$error.float">
Invalid Amount!
</span>
</div>
</div>
</form>
You can see the working demo on JSFiddle.
I hope that this helps you.
UPDATE 2015-03-11
Post has been updated with a fix to a bug that Cooper Sellers found (you can see the details at the comment feed below).