0

So I have a decimal value in controller like this:

// Controller
var MyController = function($scope) {
    ...
    $scope.percentValue = 0.05; // can be stored
    ...
};

<!-- View -->
<span>{{percentValue}}</span>
<input ng-model="percentValue" />

With the above code, the value in the input element is 0.05 - however, I want to allow a user to enter an integer value like 5.

So if the $scope.percentValue is 0.05, I want to show it as 5 in the input element. And if a user enters 5, the $scope.percentValue should be 0.05.

However, the tricky thing here is I only want to update the view value - meaning that the span element should still show 0.05. Only the value in the input element should be 5.

I am trying to achieve this with ngModel, but I am still struggling.

This is what I have now:

var MyDirective = function() {
    function link(scope, element, attrs, ngModel) {
        ngModel.$render = function() {
            element.val(ngModel.$viewValue || '');
        };

        ngModel.$formatters.push(function (value) {
            return value * 100;
        });

        element.on('change blur', function() {
            ngModel.$setViewValue(element.val());
        }); 
    }

    return {
        restrict: 'A',
        require: '?ngModel',
        scope: {},
        link: link
    };
};

Please advise!!

MichaelSolati
  • 2,847
  • 1
  • 17
  • 29
Kimchi Man
  • 1,131
  • 3
  • 13
  • 24
  • try a filter instead. – Claies Jun 14 '17 at 23:50
  • 1
    @KimchiMan, you're already using `$formatters` to transform the model representation for display, so just simply define a `$parsers` to do it the other way, like so—http://plnkr.co/edit/lB6GaT1ZSrVsOi9PS1u9?p=preview – miqh Jun 15 '17 at 00:33
  • @miqid, your answer is exactly what I want - could you add the code in the answer section? I will mark it as the answer – Kimchi Man Jun 15 '17 at 14:15
  • @miqid also, I wonder if there is a way to achieve this without using `value / 100` – Kimchi Man Jun 15 '17 at 14:54
  • 1
    @KimchiMan, are there any restrictions on what a user is expected, or allowed, to enter in that input? Any other context for what you're building might also help. If `$formatters` is already doing `value * 100`, I don't see why `value / 100` doesn't make sense. – miqh Jun 15 '17 at 15:03
  • @miqid Yeah - when I saw the cycle of $formatters and $parser, it does make sense - thanks for the help. – Kimchi Man Jun 16 '17 at 18:38

4 Answers4

1

Including my comment as an answer because it seemed to help. :-)

To summarise: since you've already provided a $formatters function for your directive, which converts a model value ($modelValue) to displayed form ($viewValue), it's simply a matter of providing a $parsers function to do the reverse and convert any user input back to the model value.

Example Plunker

miqh
  • 3,624
  • 2
  • 28
  • 38
0

What you're trying to achieve is probably possible, but I would find it really confusing to read the code. The simplest solution that I think would solve your problem and maintain readability is to store an integer value (5) in $scope.percentValue, so that ng-model is always dealing with an integer when typing and displaying the value in the <input>. Then create a custom filter and use it to output the value as 0.05 in the <span>.

Edit: adding a concrete code example. Play with it here: https://plnkr.co/edit/C1cX2L9B2GM2yax1rw7Z?p=preview

JS:

var MyController = function ($scope) {
  $scope.percentValue = 5;
};

function formatPercent (input) {
  return input / 100;
}

var myApp = angular.module('MyApp', []);
myApp.filter('percent', function () { return formatPercent });
myApp.controller('MyController', ['$scope', MyController]);

HTML:

<body ng-controller="MyController">
  <span>{{ percentValue | percent }}</span>
  <input ng-model="percentValue">
</body>
bkbooth
  • 498
  • 3
  • 13
0

I'd create a filter for percentage :

angular.module('myModule')
.filter('percentage', ['$filter', function($filter) {
    return function(input, decimals) {
        return $filter('number')(input*100, decimals)+'%';
    };
}]);

The input will store integer (such as 5)

<input ng-model="percentValue" />

But I'll add a filter to the span part :

<span>{{percentValue | percentage:2}}</span>

Credit to https://stackoverflow.com/a/21727765/3687474 for the filter directive.

aorfevre
  • 5,034
  • 3
  • 21
  • 51
0

Other than creating a filter you can also calculate on the template

<span>{{percentValue * 100}}</span>

Icycool
  • 7,099
  • 1
  • 25
  • 33