I want to create a directive that will behave as follows... On the HTML side:
<input data-ng-model="modelLogistics.inputValue1"
data-currency="{decSep:',' , thSep:'.'}">
Angular-wise, on the user side of code we would have something like:
controllerLogistics(...) {
$scope.modelLogistics = {};
$scope.modelLogistics.inputValue1 = 1234.23;
...
}
Now for the tough part: I want the input control to behave in two ways, depending on whether it has the focus or not:
- If the control has the focus, then it should display the number using only the decimal separator (decSep) and ignoring the thousand separator (thSep) - so the 1234.23 would appear in the input text that the user edits as "1234,23" (because decSep is set to ',' in the HTML directive).
- If the control loses the focus, then it should display the number using both the decimal separator (decSep) and the thousand separator (thSep) - so the 1234.23 would appear in the input text that the user sees as "1.234,23" (thSep is set to '.' in the HTML directive).
My code so far is this:
function currency() {
return {
require: '?ngModel',
link: function(scope:ng.IScope, element, attrs, ngModel) {
if(!ngModel) return; // do nothing if no ng-model
var options = scope.$eval(attrs.currency);
if (options === undefined) options = {};
if (options.decSep === undefined) options.decSep = ',';
if (options.thSep === undefined) options.thSep = '.';
element.blur(function(e) {
var parts = (ngModel.$viewValue || '').split(options.decSep);
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, options.thSep);
element.val( parts.join(options.decSep));
});
ngModel.$render = () => {
element.val(ngModel.$viewValue || '');
}
}
}
...and it works - provided that (a) my model is a string, not a number, and (b) I initialize the model with a "valid" number as per the directive specs in the HTML - that is, using model values like "1234,23" and not the number 1234.23
I am having difficulty figuring out how to change the implementation to have an underlying number (not a string) and automatically using the two modes (edit/view). I have seen the angular filters (i.e. the '|' syntax in things like '{{model.value | something}}' but I am not sure whether it fits with what I am trying to do...
Any help most appreciated.
EDIT
I have seen other currency solutions that use $formatters and $parsers - but in my case, I can't use this pattern, because the $viewValue depends not just on the $modelValue, but also on whether the control has the focus or not. That is, if I just add a formatter that checks whether the element is in focus or not, that will work the first time only - when the user clicks on some other component and the focus is lost, the model hasn't changed - yet the view needs to be updated.