javascript – Currency masking issue in input

Question:

I have a problem with the currency mask with AngularJS.

I found this thread on Stackoverflow in English. The mask works fine by typing in the input and it arrives right in the controller , but when I send formatted from the controller to the screen, it doesn't scroll.

Here 's an example.

  • Directive code snippet
    app.directive('format', ['$filter',
        function ($filter) {
            return {
                require: '?ngModel',
                link: function (scope, elem, attrs, ctrl) {
                    if (!ctrl) return;

                    ctrl.$formatters.unshift(function (a) {
                        return $filter(attrs.format)(ctrl.$modelValue)
                    });

                    ctrl.$parsers.unshift(function (viewValue) {
                        elem.priceFormat({
                            prefix: '',
                            centsSeparator: ',',
                            thousandsSeparator: '.'
                        });

                        return elem[0].value;
                    });
                }
            };
        }
    ]);
  • page code
    <!DOCTYPE html>
    <html ng-app="plunker">

    <head>
      <meta charset="utf-8" />
      <title>AngularJS Plunker</title>
      <script>
        document.write('<base href="' + document.location + '" />');
      </script>
      <link href="style.css" />
      <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.3.js">    </script>
      <script data-require="angular.js@1.2.x" src="http://code.angularjs.org/1.2.9/angular.js" data-semver="1.2.9"></script>
      <script src="app.js"></script>
    </head>

    <body ng-controller="MainCtrl">

      <div>
        <br/>Original Example 
    <input type="text" ng-model="test" format="number" /> 
    <pre>{{test|json}}</pre><br/>

    Example 1<input type="text" ng-model="test_2" format="number" /> 
    <pre>{{test_2|json}}</pre><br/>

    Example 2<input type="text" ng-model="test_3" format="number" /> 
    <pre>{{test_3|json}}</pre><br/>

      </div>
    </body>

    </html>

Answer:

I don't know where you got that code from, but it's clearly inconsistent. In one function you use the standard AngularJS $filter , in the other you use a jQuery plugin for number formatting.

The $filter only runs at the beginning, with the numbers that are already defined in the $scope , the other runs with each change.

Although I think it's not a good idea to mix jQuery plugins that handle DOM elements mixed with AngularJS filters, if you use the same function in both cases it works:

app.directive('format', ['$filter',
  function($filter) {
    return {
      require: '?ngModel',
      link: function(scope, elem, attrs, ctrl) {
        if (!ctrl) return;


        ctrl.$formatters.unshift(function(a) {
          elem[0].value = ctrl.$modelValue
          elem.priceFormat({
            prefix: '',
            centsSeparator: ',',
            thousandsSeparator: '.'
          });
          return elem[0].value;
        });

        ctrl.$parsers.unshift(function(viewValue) {
          elem.priceFormat({
            prefix: '',
            centsSeparator: ',',
            thousandsSeparator: '.'
          });
          return elem[0].value;
        });
      }
    };
  }
]);

Plunker .

EDITION:

Here's a better way to do this thing:

Define a filter to do the conversion by partially copying the jQuery plugin code:

app.filter('priceformat', function () {
      var is_number = /[0-9]/;
      var prefix = ''
      var suffix = ''
      var centsSeparator = ','
      var thousandsSeparator = '.'
      var limit = false
      var centsLimit = 2
      var clearPrefix = false
      var clearSufix = false
      var allowNegative = false
      var insertPlusSign = false
      if (insertPlusSign) allowNegative = true;

      function to_numbers(str) {
        var formatted = '';
        for (var i = 0; i < (str.length); i++) {
          char_ = str.charAt(i);
          if (formatted.length == 0 && char_ == 0) char_ = false;
          if (char_ && char_.match(is_number)) {
            if (limit) {
              if (formatted.length < limit) formatted = formatted + char_
            } else {
              formatted = formatted + char_
            }
          }
        }
        return formatted
      }

      function fill_with_zeroes(str) {
        while (str.length < (centsLimit + 1)) str = '0' + str;
        return str
      }

      return function (str) {
        var formatted = fill_with_zeroes(to_numbers(str));
        var thousandsFormatted = '';
        var thousandsCount = 0;
        if (centsLimit == 0) {
          centsSeparator = "";
          centsVal = ""
        }
        var centsVal = formatted.substr(formatted.length - centsLimit, centsLimit);
        var integerVal = formatted.substr(0, formatted.length - centsLimit);
        formatted = (centsLimit == 0) ? integerVal : integerVal + centsSeparator + centsVal;
        if (thousandsSeparator || $.trim(thousandsSeparator) != "") {
          for (var j = integerVal.length; j > 0; j--) {
            char_ = integerVal.substr(j - 1, 1);
            thousandsCount++;
            if (thousandsCount % 3 == 0) char_ = thousandsSeparator + char_;
            thousandsFormatted = char_ + thousandsFormatted
          }
          if (thousandsFormatted.substr(0, 1) == thousandsSeparator) thousandsFormatted = thousandsFormatted.substring(1, thousandsFormatted.length);
          formatted = (centsLimit == 0) ? thousandsFormatted : thousandsFormatted + centsSeparator + centsVal
        }
        if (allowNegative && (integerVal != 0 || centsVal != 0)) {
          if (str.indexOf('-') != -1 && str.indexOf('+') < str.indexOf('-')) {
            formatted = '-' + formatted
          } else {
            if (!insertPlusSign) formatted = '' + formatted;
            else formatted = '+' + formatted
          }
        }
        if (prefix) formatted = prefix + formatted;
        if (suffix) formatted = formatted + suffix;
        return formatted
      }
})

(Here is the direct values ​​in the code, but you can do different)

Then use this filter in your directive :

  ctrl.$formatters.unshift(function(a) {
     return $filter('priceformat')(ctrl.$modelValue)
  });
  ctrl.$parsers.unshift(function(viewValue) {
     return $filter('priceformat')(viewValue)
  });

Plunker.

Scroll to Top