Currency mask problem in input

Asked

Viewed 6,542 times

4

I have a problem with the coin mask with Angularjs.

I found this thread in Stackoverflow in English. The mask works beauty by typing in input and arrives right in the controller, but when I send formatted controller to the screen does not roll.

Here have an example.

  • Excerpt from the code of Directive
    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 rel="stylesheet" href="style.css" />
      <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.3.js">    </script>
      <script data-require="[email protected]" 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>
  • I didn’t understand the problem. The example here is working perfectly, both the input as to the pre with the value below.

  • take a look at example 2, command formatted in the Brazilian style '', '999.999,99', only that it does not appear in the input, but in example 1 it appears in the field but because the formatting is in the American style','999,999.99'.

2 answers

2


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

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

Although I think it’s not a good idea to mix jQuery plugins that deal with elements in the DOM mixed with Angularjs Filters, if you use the same function in both cases the thing 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 make the conversion by partially copying the code from the jQuery plugin:

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.

  • I got the idea @Giovanni, thanks man. I found this code in Stackoverflow in English on a pole over mask, and of the codes that to format decimal value, this was the one that most approached the need

  • Ah, yeah. I’d forgotten about the pole you linked there.

  • I put a better way for you to format the field that dispenses this horrible use of jQuery plugin, look there, @Calazans.

1

Here I created a function to format.

//Função formatação e Mascara de input.
function funSftMask(value, format) {
    /* Aqui verifica se o campo aceita mais de um formato.
    Ex:(99)99999-9999|(99)9999-9999 sepada por pipe(|)  */
    format = format.indexOf("|") !== -1 ? format.split("|") : format;
    /* Varre a lista e verifica o valor passado e aplica a mascara conforme o tamanho da string. */
    if(format instanceof Array){
        for(var i = 0; i < format.length; i++){
            if(format[i].replace(/[^\d]+/g, '').length === value.length){
                format = format[i];
                break;
            }
        }
    }
    /* Caso não indentifique um tamanho padrão seleciona o primeiro  */
    if(format instanceof Array){
        format = format[1];
    }
    value = value.split("");
    format = format.split("");
    var result = "";
    var x = 0;
    for (var i = 0; i < format.length; i++) {
        if (format[i] !== "9") {
            x--;
        }
        if (x >= value.length)
            break;
        result += format[i] === '9' ? value[x] : format[i];
        x++;
    }
    return result;
}

Here the input that received the mask

<input type="text" placeholder="Somente numeros" sft-mack="(99)99999-9999|(99)9999-9999" />

here the directive that will format the input as it is typing.

nomedaApp.directive('sftMack', function () {
    return {
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {
            var id = '#' + attrs.id;
            elem.add(id).on('keyup', function () {
                var x = funSftMask(elem.val().replace(/[^\d]+/g, ''), attrs.sftMack);
                elem.val(x);
            });
        }
    };
});

Browser other questions tagged

You are not signed in. Login or sign up in order to post.