SgNumberInput directive

by David Votrubec

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<div ng-controller="MyCtrl">
    
    <div class="header">
        AngularJs directive for automatic formatting of numeric values in input fields.        
    </div>
    
    
    Without decimal places
    <input type='text' sg-number-input ng-model="numericValue"/>
    <br/>
    
    With 2 decimal places
    <input type='text' sg-number-input fraction-size="2" ng-model="numericValue"/>
</div>

CSS

.header {
    font-weight: bold;
    margin-bottom: 15px;
    padding: 15px;    
}

JavaScript

var myApp = angular.module('myApp', []);
 
myApp.controller('MyCtrl', function($scope) {
  $scope.numericValue = 12345678;
});

//Written by David Votrubec from ST-Software.com
//Inspired by http://jsfiddle.net/KPeBD/2/
//Up-to-date code can be found on GitHub https://github.com/ST-Software/STAngular/blob/master/src/directives/SgNumberInput
myApp.directive('sgNumberInput', ['$filter', '$locale', function ($filter, $locale) {
        return {
            require: 'ngModel',
            restrict: "A",
            link: function ($scope, element, attrs, ctrl) {
                var fractionSize = parseInt(attrs['fractionSize']) || 0;
                var numberFilter = $filter('number');
                //format the view value
                ctrl.$formatters.push(function (modelValue) {
                    var retVal = numberFilter(modelValue, fractionSize);
                    var isValid = isNaN(modelValue) == false;
                    ctrl.$setValidity(attrs.name, isValid);
                    return retVal;
                });
                //parse user's input
                ctrl.$parsers.push(function (viewValue) {
                    var caretPosition = getCaretPosition(element[0]), nonNumericCount = countNonNumericChars(viewValue);
                    viewValue = viewValue || '';
                    //Replace all possible group separators
                    var trimmedValue = viewValue.trim().replace(/,/g, '').replace(/`/g, '').replace(/'/g, '').replace(/\u00a0/g, '').replace(/ /g, '');
                    //If numericValue contains more decimal places than is allowed by fractionSize, then numberFilter would round the value up
                    //Thus 123.109 would become 123.11
                    //We do not want that, therefore I strip the extra decimal numbers
                    var separator = $locale.NUMBER_FORMATS.DECIMAL_SEP;
                    var arr = trimmedValue.split(separator);
                    var decimalPlaces = arr[1];
          ...