Skip to content

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:

  1. Display numbers with 2 fractional digits by default.
  2. 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).

Free Developer Insights

Don’t miss out on the awesome things that got my attention to help me simplify my life as a developer. No spam, ever.

    I will not send you spam.

    Unsubscribe at any time.