Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS - How to apply currency filter on textbox as I type?

My project has a requirement to show amount field in currency format. I can achieve this onblur event, but let me know if this can be achieved using filters or some other AngularJS technique.

I have the following textbox:

<input type="text" class="form-control" id="MyAmount" name="MyAmount" ng-model="MyAmount" />

I want to convert the value inside this text box to follow currency format. So, if I type 200000, it should make is $200,000.00 as soon as I type or while I am typing.

I used the following technique and applied a filter,

<input type="text" class="form-control" id="MyAmount" name="MyAmount" ng-model="MyAmount"
                            value="{{MyAmount | currency}}" />

but it only converts for the first key I type, like it converts 2 to $2.00 and then it clears the value (as I guess it finds this updated value as not a number?)

Update: I am able to format it live using a custom filter, but that filter is not working properly in all the cases and when I save the value, I am getting values with $ and commas in the amount and not just the numeric value. I will try more.

like image 714
Pawan Pillai Avatar asked Dec 02 '22 19:12

Pawan Pillai


2 Answers

It is a rather non-trivial problem. For the main part of the functionality, you need to use ngModelController's $formatters and $parsers properties to register listeners to handle the changes in $modelValue and $viewValue respectively.

  1. When the $modelValue changes, you need to filter it using the currency filter before displaying it to the view.

  2. When the $viewValue changes, you need to convert it to a number (I thought it makes more sense to store the model value as number, not as a formatted string), filter that number through the currency filter and update the $viewValue (if necessary).

That is not particularly difficult. The tricky part is that updating the element's value, moves the cursor at the end, so you need to manually re-position the caret.

My attempt resulted in the following Directive Definition Object

{
  restrict: 'A',
  require: 'ngModel',
  link: function postLink(scope, elem, attrs, modelCtrl) {    
    modelCtrl.$formatters.push(filterFunc);
    modelCtrl.$parsers.push(function (newViewValue) {
      var newModelValue = toNumber(newViewValue);
      modelCtrl.$viewValue = filterFunc(newModelValue);
      var pos = getCaretPosition(elem[0]);
      elem.val(modelCtrl.$viewValue);
      var newPos = pos + modelCtrl.$viewValue.length -
                         newViewValue.length;
      setCaretPosition(elem[0], newPos);
      return newModelValue;
    });
  }
};

See, also, this short demo. It's not perfect, but it's a good start. BTW, I "borrowed" the get/setCaretPosition() functions from AngularUI's uiMask directive.

like image 177
gkalpak Avatar answered Dec 28 '22 05:12

gkalpak


You can also use the fcsa-number directive that provides this for you automatically. It's as easy as adding the fcsa-number attribute to the input element.

<input type="text" fcsa-number />

And here is a demo

The source code and documentation is available on GitHub: https://github.com/FCSAmericaDev/angular-fcsa-number

like image 32
Paul Avatar answered Dec 28 '22 05:12

Paul