0

the context: I am developing a mobile version of my app. I want a user to be able to enter numeric fields with their numeric keybord of their phone/tablet. AngularJS makes input fields with type = "number" unreachable for any non-integer data (which is any, because input is a string).

the idea: I want to make a directive that will somehow (using $watch or $parsers or any other ancient sorcery) convert input string to number.

the issue: My directive does not trigger changes of $watch when I type anything in the input field. But when I change scope field from my cotroller $watch is triggered as planed.

controller:

        // code minimized and omitted for clarity
        .controller('carController', ['$scope', function ($scope) {
            $scope.car = {
                power : null,
                // other fields
            }
        }]);

directive

angular.module('numeric', []).directive('numeric', function () {
    return {
        restrict: 'A',
        require: 'ngModel',

        scope: {
            model: '=ngModel'
        },
        link: function (scope, element, attrs, ngModelCtrl) {
            // parsers does not affect anything
            ngModelCtrl.$parsers.push(function(value) {
                return parseInt(value);
            });

            // watcher does not watch
            scope.$watch('model', function(newVal, old) {
                if (typeof newVal == 'string') {
                    scope.car.power = parseInt(newVal);
                }
            }, true);

        }
    };
});

html

    <div ng-controller="carController">
     <input   
            ng-model="car.power"                      
            numeric
            name="power"
            type="number"
            pattern="[0-9]">
       </div>

Here is a fiddle that demonstrates such behavior http://jsfiddle.net/xo94sw7m/1/

the question: what am I missing and how to make directive work as planned?


What I have tried: using $formatters-$parsers,using different approaches to $watch (using scope:false, isolated scope, trying to watch scope changes using attrs and etc), nothing seems to work so far

5
  • I don't see the problem, <input type="number"> fully supports floats Commented Mar 20, 2017 at 12:43
  • If you read the question or visit fiddle link you probably will see the problem. Commented Mar 20, 2017 at 12:45
  • I read the question and visited the fiddle, but why are you storing float as string? Just store it as float. Commented Mar 20, 2017 at 13:29
  • I am not storing float as string :) the only float in my question is parseFloat() and that is just bad copy-paste, I replaced in with parseInt(). But it does not make any difference - type=number will block .... wait. It seems that u were right, i have just deleted my directive and input is accepted jsfiddle.net/aqkobhux I don't understand what originally was wrong then... Commented Mar 20, 2017 at 13:44
  • @RonDadon it appears that problem was in pattern="[0-9]" attribute... Thank you for your help! Commented Mar 20, 2017 at 13:51

1 Answer 1

1
myApp.directive('number', ['$parse', function($parse) {
    return {
        require: 'ngModel',
        link: function(scope, element, attrs, ngModelController) {

            ngModelController.$parsers.push(function(data) {
                return parseInt(data);
            });
            ngModelController.$formatters.push(function(data) {
                if (data) {
                    var model = $parse(attrs['ngModel']);
                    model.assign(scope, parseInt(data));
                }
                return parseInt(data);

            });
        }
    }
}]);

Here is working fiddle

Sign up to request clarification or add additional context in comments.

2 Comments

Could you, please, provide some explanation for $formatters part ?
Formatters are invoked when the model is modified in the code.You can check this link stackoverflow.com/a/22843592/5621827 for more info.Also please marked this as accepted ans if it works for you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.