71

In angularjs is there any functionality available that allows only numbers to be typed into a text box like

Ali Hasan
  • 713
  • 1
  • 5
  • 4
  • 11
  • it is for validation.works on submission of form.i want to disallow user enter any other values than number/integer..like this http://www.texotela.co.uk/code/jquery/numeric/ – Ali Hasan Apr 18 '13 at 19:26
  • 1
    possible duplicate of [How do I restrict an input to only accept numbers?](http://stackoverflow.com/questions/14615236/how-do-i-restrict-an-input-to-only-accept-numbers) – Mark Rajcok Apr 19 '13 at 15:43
  • Is there an update to this question that allows for periods, commas as a user types & copy-and-pasting? – RLH Jun 15 '22 at 20:31

23 Answers23

65

This code shows the example how to prevent entering non digit symbols.

angular.module('app').
  directive('onlyDigits', function () {

    return {
        restrict: 'A',
        require: '?ngModel',
        link: function (scope, element, attrs, modelCtrl) {
            modelCtrl.$parsers.push(function (inputValue) {
                if (inputValue == undefined) return '';
                var transformedInput = inputValue.replace(/[^0-9]/g, '');
                if (transformedInput !== inputValue) {
                    modelCtrl.$setViewValue(transformedInput);
                    modelCtrl.$render();
                }
                return transformedInput;
            });
        }
    };
});
Ryan Langton
  • 6,294
  • 15
  • 53
  • 103
Anton
  • 2,535
  • 2
  • 25
  • 28
  • 1
    Thanks for this. I simplified the non-digit stripping and wrote a test: https://gist.github.com/henrik/769d49136744ddcaa1dc At the time of writing, the code is JS but the test is CoffeeScript. Soon both will be CoffeeScript, I think. – Henrik N Aug 26 '14 at 11:54
  • double tapping a letter key will make this fail – Blowsie Sep 02 '15 at 13:57
  • 8
    as Blowsie notes, this code doesn't work in all cases.. here is a working jsfiddle which I'm trying to update this answer to use: http://jsfiddle.net/thomporter/DwKZh/ – Ryan Langton Oct 08 '15 at 20:20
  • 1
    The directive should be used with ng-trim=false if you want to explicitly disable input of whitespaces – eternity Jul 25 '17 at 15:01
  • The users are able to type whitespaces. Add `attrs.$set('ngTrim', "false");` before parsers for preventing whitespaces. – AhmadReza Payan Nov 26 '17 at 19:09
43

HTML

 <input type="text" name="number" only-digits>

// Just type 123

  .directive('onlyDigits', function () {
    return {
      require: 'ngModel',
      restrict: 'A',
      link: function (scope, element, attr, ctrl) {
        function inputValue(val) {
          if (val) {
            var digits = val.replace(/[^0-9]/g, '');

            if (digits !== val) {
              ctrl.$setViewValue(digits);
              ctrl.$render();
            }
            return parseInt(digits,10);
          }
          return undefined;
        }            
        ctrl.$parsers.push(inputValue);
      }
    };
});

// type: 123 or 123.45

 .directive('onlyDigits', function () {
    return {
      require: 'ngModel',
      restrict: 'A',
      link: function (scope, element, attr, ctrl) {
        function inputValue(val) {
          if (val) {
            var digits = val.replace(/[^0-9.]/g, '');

            if (digits.split('.').length > 2) {
              digits = digits.substring(0, digits.length - 1);
            }

            if (digits !== val) {
              ctrl.$setViewValue(digits);
              ctrl.$render();
            }
            return parseFloat(digits);
          }
          return undefined;
        }            
        ctrl.$parsers.push(inputValue);
      }
    };
 });
Gourneau
  • 12,660
  • 8
  • 42
  • 42
My Mai
  • 1,073
  • 9
  • 10
  • 2
    Your second example (// type: 123 or 123.45) allows multiple decimal places to be entered, e.g. 11.22..33.....444 will return valid. – Paul McClean Mar 13 '15 at 11:37
  • 2
    I think we can handle that using the following if (digits.split('.').length > 2) digits = digits.substring(0, digits.length - 1); – Matt May 03 '15 at 11:45
  • 1
    Why the code is so lengthy in angularjs when it is simple in normal javascript for the same requirement?? – kittu Jun 11 '15 at 12:57
  • How to limit this to 2 digits only? – Bharath Aug 18 '16 at 19:29
  • @Bharath for restrict only 2 decimal --> if (digits.split('.').length > 1) { digits = digits.substring(0, digits.indexOf('.') + 3); } – Aravinthan K May 15 '18 at 07:09
37

I just used ng-keypress in the directive for my input.

HTML:

<input type="text" ng-keypress="filterValue($event)"/>

JS:

$scope.filterValue = function($event){
        if(isNaN(String.fromCharCode($event.keyCode))){
            $event.preventDefault();
        }
};
samnau
  • 683
  • 7
  • 7
  • 2
    Whilst this isn't really "the angular way" it seems like a relatively safe option to prevent the user input – Blowsie Sep 02 '15 at 14:00
  • 4
    This seems very simple, though the non angular way might stop some, I definitely liked this approach. Had to add 2 other cases which had to be allowed though, event.which === 8 and event.which === 46 (for backspace and delete respectively) – Vikram Sep 09 '15 at 10:37
  • Nice solution! I used the @Markiv comment to improve your code in a [new answer](https://stackoverflow.com/questions/16091218/angularjs-allows-only-numbers-to-be-typed-into-a-text-box#answer-35823435) that allows edition, submit and navigation. – Leopoldo Sanczyk Mar 06 '16 at 05:24
  • I liked this solution, and allthough the value is trimmed => I changed the condition a little bit to prevent pressing space bar: if( isNaN(String.fromCharCode($event.keyCode)) || $event.keyCode === 32) – Dimi Apr 23 '17 at 22:48
  • Keypress event is deprecated, some of the browsers(namely Chrome) don't support it. Keydown event is also fishy - on some devices, Nexus4, it doesn't report correct key codes. The only real way to do it (afaik) is to not use characters, but the actual real text. – Erti-Chris Eelmaa Jun 06 '17 at 08:10
26

This functionality just what you need. http://docs.angularjs.org/api/ng.directive:input.number

EDIT:

You can wrap the jquery plugin into directive. I created an example here: http://jsfiddle.net/anazimok/jTJCF/

HTML:

<div ng-app="myApp">
    <div>
        <input type="text" min="0" max="99" number-mask="" ng-model="message">
            <button ng-click="handleClick()">Broadcast</button>
    </div>

</div>

CSS:

.ng-invalid {
    border: 1px solid red;
}

JS:

// declare a module
var app = angular.module('myApp', []);

app.directive('numberMask', function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            $(element).numeric();
        }
    }
});
Bucket
  • 7,415
  • 9
  • 35
  • 45
anazimok
  • 1,750
  • 2
  • 20
  • 33
  • 17
    Not quite the OP is asking for. Your solution provides input validation (ie. shows error when non-number is detected) but users can still type non-number in the textbox. – tamakisquare Apr 18 '13 at 19:21
  • 1
    @AliHasan This shouldn't be the correct answer as it does not answer the question. – Bucket Aug 15 '17 at 14:21
21

This is the simplest and fastest way, for allowing the Number input only.

<input type="text" id="cardno" placeholder="Enter a Number" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required>

Thanks

Sijan Gurung
  • 727
  • 5
  • 12
7

To build on Anton's answer a little --

angular.module("app").directive("onlyDigits", function ()
{
    return {
        restrict: 'EA',
        require: '?ngModel',
        scope:{
            allowDecimal: '@',
            allowNegative: '@',
            minNum: '@',
            maxNum: '@'
        },

        link: function (scope, element, attrs, ngModel)
        {
            if (!ngModel) return;
            ngModel.$parsers.unshift(function (inputValue)
            {
                var decimalFound = false;
                var digits = inputValue.split('').filter(function (s,i)
                {
                    var b = (!isNaN(s) && s != ' ');
                    if (!b && attrs.allowDecimal && attrs.allowDecimal == "true")
                    {
                        if (s == "." && decimalFound == false)
                        {
                            decimalFound = true;
                            b = true;
                        }
                    }
                    if (!b && attrs.allowNegative && attrs.allowNegative == "true")
                    {
                        b = (s == '-' && i == 0);
                    }

                    return b;
                }).join('');
                if (attrs.maxNum && !isNaN(attrs.maxNum) && parseFloat(digits) > parseFloat(attrs.maxNum))
                {
                    digits = attrs.maxNum;
                }
                if (attrs.minNum && !isNaN(attrs.minNum) && parseFloat(digits) < parseFloat(attrs.minNum))
                {
                    digits = attrs.minNum;
                }
                ngModel.$viewValue = digits;
                ngModel.$render();

                return digits;
            });
        }
    };
});
Craig
  • 770
  • 3
  • 14
  • 26
  • 1
    Instead of `ngModel.$viewValue = digits` you should use `ngModel.$setViewValue(digits)` so it will hit the rest of ngModelController and ngForm hooks. I needed this since it was a required field and when i entered a letter (which didn't show), the form was marked valid - incorrectly. – Chaz Feb 13 '15 at 20:28
  • the problem with this directive is if you type legal number and by mistake you type letter your field will removed. – orikoko Feb 23 '15 at 14:53
7

My solution accept Copy&Paste and save the position of the caret. It's used for cost of products so allows positive decimal values only. Can be refactor very easy to allow negative or just integer digits.

angular
        .module("client")
        .directive("onlyNumber", function () {
            return {
                restrict: "A",
                link: function (scope, element, attr) {
                    element.bind('input', function () {
                        var position = this.selectionStart - 1;

                        //remove all but number and .
                        var fixed = this.value.replace(/[^0-9\.]/g, '');  
                        if (fixed.charAt(0) === '.')                  //can't start with .
                            fixed = fixed.slice(1);

                        var pos = fixed.indexOf(".") + 1;
                        if (pos >= 0)               //avoid more than one .
                            fixed = fixed.substr(0, pos) + fixed.slice(pos).replace('.', '');  

                        if (this.value !== fixed) {
                            this.value = fixed;
                            this.selectionStart = position;
                            this.selectionEnd = position;
                        }
                    });
                }
            };
        });

Put on the html page:

<input type="text" class="form-control" only-number ng-model="vm.cost" />
Carlos Toledo
  • 2,519
  • 23
  • 23
2

This is the method that works for me. It's based in samnau anwser but allows to submit the form with ENTER, increase and decrease the number with UP and DOWN arrows, edition with DEL,BACKSPACE,LEFT and RIGHT, and navigate trough fields with TAB. Note that it works for positive integers such as an amount.

HTML:

<input ng-keypress="onlyNumbers($event)" min="0" type="number" step="1" ng-pattern="/^[0-9]{1,8}$/" ng-model="... >

ANGULARJS:

$scope.onlyNumbers = function(event){   
    var keys={
        'up': 38,'right':39,'down':40,'left':37,
        'escape':27,'backspace':8,'tab':9,'enter':13,'del':46,
        '0':48,'1':49,'2':50,'3':51,'4':52,'5':53,'6':54,'7':55,'8':56,'9':57
    };
    for(var index in keys) {
        if (!keys.hasOwnProperty(index)) continue;
        if (event.charCode==keys[index]||event.keyCode==keys[index]) {
            return; //default event
        }
    }   
    event.preventDefault();
};
Leopoldo Sanczyk
  • 1,529
  • 1
  • 26
  • 28
2

Based on djsiz solution, wrapped in directive. NOTE: it will not handle digit numbers, but it can be easily updated

angular
        .module("app")
        .directive("mwInputRestrict", [
            function () {
                return {
                    restrict: "A",
                    link: function (scope, element, attrs) {
                        element.on("keypress", function (event) {
                            if (attrs.mwInputRestrict === "onlynumbers") {
                                // allow only digits to be entered, or backspace and delete keys to be pressed
                                return (event.charCode >= 48 && event.charCode <= 57) ||
                                       (event.keyCode === 8 || event.keyCode === 46);
                            }
                            return true;
                        });
                    }
                }
            }
        ]);

HTML

 <input type="text"
        class="form-control"
        id="inputHeight"
        name="inputHeight"
        placeholder="Height"
        mw-input-restrict="onlynumbers"
        ng-model="ctbtVm.dto.height">
igorGIS
  • 1,888
  • 4
  • 27
  • 41
2

Simply use HTML5

<input type="number" min="0"/>
Rohidas Kadam
  • 428
  • 5
  • 12
  • Yes, *type="number"* will definitely work great. But it fails to render properly when we this kind of input with bootstrap input groups. – Praveen Apr 10 '17 at 09:18
1

You can check https://github.com/rajesh38/ng-only-number

  1. It restricts input to only numbers and decimal point in a textbox while typing.
  2. You can limit the number of digits to be allowed before and after the decimal point
  3. It also trims the digits after the decimal point if the decimal point is removed from the textbox e.g. if you have put 123.45 and then remove the decimal point it will also remove the trailing digits after the decimal point and make it 123.
Rajesh Paul
  • 6,793
  • 6
  • 40
  • 57
1

You could do something like this: Use ng-pattern with the RegExp "/^[0-9]+$/" that means only integer numbers are valid.

<form novalidate name="form">
    <input type="text" data-ng-model="age" id="age" name="age" ng-pattern="/^[0-9]+$/">
    <span ng-show="form.age.$error.pattern">The value is not a valid integer</span>
</form>
Victor Oliveira
  • 545
  • 7
  • 13
1

This solution will accept only numeric, '.' and '-'

Also this restricts the space entry on text box. I had used the directive to achieve the same.

Please have the solution on below working example.

http://jsfiddle.net/vfsHX/2697/

HTML:

<form ng-app="myapp" name="myform" novalidate> 
<div ng-controller="Ctrl">
<input name="number" is-number ng-model="wks.number">
<span ng-show="!wks.validity">Value is invalid</span>
</div>

JS:

var $scope;
var app = angular.module('myapp', []);

app.controller('Ctrl', function($scope) {
    $scope.wks =  {number: 1, validity: true}
});

app.directive('isNumber', function () {
    return {
        require: 'ngModel',
        link: function (scope, element, attrs, ngModel) {   
        element.bind("keydown keypress", function (event) {
          if(event.which === 32) {
            event.returnValue = false;
            return false;
          }
       }); 
            scope.$watch(attrs.ngModel, function(newValue,oldValue) {
                var arr = String(newValue).split("");
                if (arr.length === 0) return;
                if (arr.length === 1 && (arr[0] == '-' || arr[0] === '.' )) return;
                if (arr.length === 2 && newValue === '-.') return;
                if (isNaN(newValue)) {
                    //scope.wks.number = oldValue;
                    ngModel.$setViewValue(oldValue);
                                    ngModel.$render();
                }
            });

        }
    };
});
Suve
  • 36
  • 4
1

It's simple and understandable. Just copy paste this code and your issue will get resolved.For more conditions just change the value in pattern.and your work will done.

<input type="text"  pattern="[0-9]{0,}" oninvalid="this.setCustomValidity('Please enter only numeric value. Special character are not allowed.')" oninput="setCustomValidity('')">
1

This answer serves as a simplification and optimisation over Leopoldo's answer.

Trigger a function from your input on every keydown like this:

<input type="text" ng-keydown="onlyNumbers($event);"/>

You can describe the function in this manner in your controller

$scope.onlyNumbers = function(event){    
    // 'up': 38,'right':39,'down':40,'left':37,
    // 'escape':27,'backspace':8,'tab':9,'enter':13,'del':46,
    // '0':48,'1':49,'2':50,'3':51,'4':52,'5':53,'6':54,'7':55,'8':56,'9':57
    var keys = { 38:true,39:true,40:true,37:true,27:true,8:true,9:true,13:true,
                 46:true,48:true,49:true, 50:true,51:true,52:true,53:true,
                 54:true,55:true,56:true,57:true };

    // if the pressed key is not listed, do not perform any action
    if(!keys[event.keyCode]) { event.preventDefault(); }
}

In case you're using Angular 2+, you can call this same function in this manner:

<input type="text" (keydown)="onlyNumbers($event);"/>

Your Angular 2+ function should look something like this:

onlyNumbers(event) { // the logic here }
Surya
  • 48
  • 7
1
<input type="phone" numbers-only >

You can use this way if you want only numbers :)

here is the the demo click

Sayed Mohd Ali
  • 2,156
  • 3
  • 12
  • 28
0

I had a similar issue and ended up hooking and event

ng-change="changeCount()" 

then:

self.changeCount = function () {
      if (!self.info.itemcount) {
        self.info.itemcount = 1;
      }
 };

So the user is defaulted to 1 if a invalid number is inserted.

leeroya
  • 485
  • 7
  • 12
0

I arraged the jQuery in this

.directive('numbersCommaOnly', function(){
   return {
     require: 'ngModel',
     link: function (scope, element, attrs, ngModel) {

        element.on('keydown', function(event) {                  
            // Allow: backspace, delete, tab, escape, enter and .
            var array2 = [46, 8, 9, 27, 13, 110, 190]
            if (array2.indexOf(event.which) !== -1 ||
                 // Allow: Ctrl+A
                (event.which == 65 && event.ctrlKey === true) ||
                 // Allow: Ctrl+C
                (event.which == 67 && event.ctrlKey === true) ||
                 // Allow: Ctrl+X
                (event.which == 88 && event.ctrlKey === true) ||
                 // Allow: home, end, left, right
                (event.which >= 35 && event.which <= 39)) {
                     // let it happen, don't do anything
                     return;
            }
            // Ensure that it is a number and stop the keypress
            if ((event.shiftKey || (event.which < 48 || event.which > 57)) && (event.which < 96 || event.which > 105)) {
                event.preventDefault();
            }
         });

     }
   };
})
Community
  • 1
  • 1
plampot
  • 46
  • 3
0
 <input type="text" ng-keypress="checkNumeric($event)"/>
 //inside controller
 $scope.dot = false
 $scope.checkNumeric = function($event){
 if(String.fromCharCode($event.keyCode) == "." && !$scope.dot){
    $scope.dot = true
 }
 else if( isNaN(String.fromCharCode($event.keyCode))){
   $event.preventDefault();
 }
0

I know this is an old post but this adaptation of My Mai's answer works nicely for me...

angular.module("app").directive("numbersOnly", function() {
  return {
    require: "ngModel",
    restrict: "A",
    link: function(scope, element, attr, ctrl) {
        function inputValue(val) {
            if (val) {
                //transform val to a string so replace works
                var myVal = val.toString();

                //replace any non numeric characters with nothing
                var digits = myVal.replace(/\D/g, "");

                //if anything needs replacing - do it!
                if (digits !== myVal) {
                    ctrl.$setViewValue(digits);
                    ctrl.$render();
                }
                return parseFloat(digits);
            }
            return undefined;
        }
        ctrl.$parsers.push(inputValue);
    }
  };
});
Janey
  • 1,260
  • 3
  • 17
  • 39
0

I have done at

.js

$scope.numberOnly="(^[0-9]+$)";

.html

<input type="text" name="rollNo" ng-model="stud.rollNo" ng-pattern="numberOnly" ng-maxlength="10" maxlength="10" md-maxlength="10" ng-required="true" >
Nilesh
  • 1,013
  • 14
  • 21
-1

Use ng-only-number to allow only numbers, for example:

<input type="text" ng-only-number data-max-length=5>
Nick is tired
  • 6,860
  • 20
  • 39
  • 51
-2
 <input
    onkeypress="return (event.charCode >= 48 && event.charCode <= 57) ||                         
    event.charCode == 0 || event.charCode == 46">
Fraser
  • 15,275
  • 8
  • 53
  • 104
rakib
  • 31
  • 3
  • 1
    Great that you answered, and while this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – Fraser Mar 19 '18 at 18:09
  • Thanks @Fraser . If you do not mind Can you help me for right ans please :) – rakib Mar 20 '18 at 03:34