TiggerToo
TiggerToo

Reputation: 669

Angular directive for displaying cents as dollars in an input

So, I have to make an input for currency that stores the value as an integer in cents. I have a directive that almost works, but not quite. The following directive successfully converts the data from the model to the view and after being changed, it successfully strips everything extraneous from what's going back to the model. The problem is that it does not update the view again when the model changes. So, if the input is showing $10.00 and I type in $10.00a, the model will correctly show 1000, but the a remains in the input field.

return {
  require: 'ngModel',
  link: function (elem, $scope, attrs, ngModel) {
    ngModel.$formatters.push(function (val) {
      return '$' + (val / 100).toFixed(2);
    });
    ngModel.$parsers.push(function (val) {
      var replaced = val.replace(/[^\d\.]/g, '');
      var split = replaced.split('.');
      var merged = split[0] + split[1].slice(0, 2)
      return Number(merged);
    });
  }
}

Upvotes: 2

Views: 800

Answers (1)

David Tao
David Tao

Reputation: 513

In order to update the viewValue you need to call these two functions in the newly pushed parser:

//update the $viewValue
ngModel.$setViewValue(displayedValue);
//reflect on the DOM element
ngModel.$render();

So the directive will look like:

.directive('myFilter', [
    function() {
            return {
            require: 'ngModel',
                link: function (elem, $scope, attrs, ngModel) {
                    ngModel.$formatters.push(function (val) {
                        return '$' + (val / 100).toFixed(2);
                    });
                    ngModel.$parsers.push(function (val) {
                        //make sure the val is string
                        val = val.toString();
                        //filter the value for displaying, so keep the '$'
                        var displayedValue = val.replace(/[^\d\.\$]/g, '');
                        var replaced = val.replace(/[^\d\.]/g, '');
                        var split = replaced.split('.');
                        var merged = split[0] + split[1].slice(0, 2);
                        var typeConverted = Number(merged);
                        //update the $viewValue
          ngModel.$setViewValue(displayedValue);
          //reflect on the DOM element
          ngModel.$render();
                        return typeConverted;
                    });
                }
            }
        }
])

And a working fiddle is here : fiddle_link

And another similar overstack post has more explanation about the reason why those two lines are need : https://stackoverflow.com/a/36653378/1300334

Hope this can help you.

Upvotes: 1

Related Questions