admin管理员组

文章数量:1389750

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 mas).

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);
            });
        }
    }
}]);

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 mas).

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);
            });
        }
    }
}]);
Share Improve this question asked Nov 25, 2014 at 19:28 GillardoGillardo 9,83818 gold badges81 silver badges152 bronze badges 6
  • With the way you've defined $parsers, the directive will store formatted numbers to the model (i.e. if you entered 123456, $modelValue will be set as 123,456, which ends up being a string) every time you edit the associated input field. Instead of using $parsers and $formatters, why not consider a $watch() on the model value instead? – miqh Commented Nov 26, 2014 at 1:45
  • I am not sure adding a watcher is the best idea. I don't like the thought of an extra watcher for each instance of the directive. I could have maybe 50 of these on screen. 50 extra watchers doesn't sound good. Must be able to do this without a watcher. – Gillardo Commented Nov 26, 2014 at 4:42
  • Well, if you insist, here's a minor change that should do the trick. You don't say anything about model validation so I assume you're OK with managing that, plnkr.co/edit/wSflQs9bXYvihL5jUrvc?p=preview – miqh Commented Nov 26, 2014 at 5:17
  • Thanks for the change, i figured the $parser change had to use parseFloat, but not the blur change so thanks. But now you have me worried, with the ment "You dont say anything about model validation..." Well i would like to use ng-required on this so i am guessing thats fine? – Gillardo Commented Nov 26, 2014 at 5:42
  • No problem, glad it helped. By validation, I was referring to how you deal with users putting in silly values into the input field. I updated my Plunker with a crude example of what you might want to do (plnkr.co/edit/wSflQs9bXYvihL5jUrvc?p=preview). You can then make use the style class ng-invalid or check ngModelController.$invalid. – miqh Commented Nov 26, 2014 at 6:08
 |  Show 1 more ment

1 Answer 1

Reset to default 3

Discussion in the question ments 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 acmodate 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

本文标签: javascriptAngularJS number format filter directive for input using NgModelStack Overflow