Gillardo
Gillardo

Reputation: 9828

AngularJS number format filter directive for input using NgModel

I would like to create a directive for an input control that formats a number with X number of decimal places when the input doesnt have focus. When the input does have focus, i would like the number to appear unformatted (no commas).

I am almost there, with the following code. When you click inside the input, the text changes and when you click out (blur event) the text formats again. However, if i change the value in the input, then the events seem to change round, and the blur event does nothing. Then if you click in the input box again, the value formats when it shouldnt, and the blur event unformats, when it should format.

To use the directive you can simply do

<input number-format ng-model="myValue" decimals="numberOfDecimals" />

Here is the directive

App.directive('numberFormat', ['$filter', '$parse', function ($filter, $parse) {
    return {
        require: 'ngModel',
        link: function (scope, element, attrs, ngModelController) {
            var decimals = $parse(attrs.decimals)(scope);

            ngModelController.$parsers.push(function (data) {
                //convert data from view format to model format
                return $filter('number')(data, decimals); //converted
            });

            ngModelController.$formatters.push(function (data) {
                //convert data from model format to view format
                return $filter('number')(data, decimals); //converted
            });

            element.bind('focus', function () {
                element.val(ngModelController.$modelValue);
            });

            element.bind('blur', function () {
                element.val(ngModelController.$viewValue);
            });
        }
    }
}]);

Upvotes: 1

Views: 12036

Answers (1)

miqh
miqh

Reputation: 3664

Discussion in the question comments appeared to have helped the OP.

$parsers was causing user-specified input values to be stored to the model value as the filter number format. For example, if 123456 was entered, the underlying model value would be set to 123,456. The point here is that the model value should be storing the raw user input, not the user input after formatting is applied. A simple implementation to parse the user input for $parsers would be to use parseFloat(), like so:

ngModelController.$parsers.push(function (data) {
    return parseFloat(data);
});

To be safe, this parsing function should be improved to accommodate for bad user input. I've provided a rudimentary example of this in my demonstration Plunker.

On blur, the value in the input field should be set to the filtered version of the model value.

DEMO

Upvotes: 3

Related Questions