¿Cómo restrinjo una entrada para que solo acepte números?

92

Estoy usando ngChange en AngularJS para activar una función personalizada que eliminará cualquier letra que el usuario agregue a la entrada.

<input type="text" name="inputName" data-ng-change="numbersOnly()"/>

El problema es que necesito apuntar a la entrada que activó numbersOnly() para poder eliminar las letras ingresadas. He buscado mucho en Google y no pude encontrar nada al respecto.

¿Que puedo hacer?

Chris Bier
fuente
Esta también es una buena solución, que no permite ingresar letras.
Himanshu Bhandari
El posible duplicado de la entrada de texto HTML solo permite la entrada numérica
Shobhit Srivastava

Respuestas:

104

De manera fácil , use type = "number" si funciona para su caso de uso:

<input type="number" ng-model="myText" name="inputName">

Otra forma fácil: ng-pattern también se puede usar para definir una expresión regular que limitará lo que está permitido en el campo. Consulte también la página del "libro de recetas" sobre formularios .

¿Hackish? way , $ mire el modelo ng en su controlador:

<input type="text"  ng-model="myText" name="inputName">

Controlador:

$scope.$watch('myText', function() {
   // put numbersOnly() logic here, e.g.:
   if ($scope.myText  ... regex to look for ... ) {
      // strip out the non-numbers
   }
})

La mejor manera es usar un $ parser en una directiva. No voy a repetir la ya buena respuesta proporcionada por @ pkozlowski.opensource, así que aquí está el enlace: https://stackoverflow.com/a/14425022/215945

Todas las soluciones anteriores implican el uso de ng-model, lo que hace que no sea thisnecesario buscar .

El uso de ng-change causará problemas. Vea AngularJS: el restablecimiento de $ scope.value no cambia el valor en la plantilla (comportamiento aleatorio)

Mark Rajcok
fuente
¡Terminé creando una directiva! Gracias por incluir la mejor forma. ¡Investigué un poco, pero aprendí mucho!
Chris Bier
1
¿Alguien capaz de expandir las desventajas de la forma "fácil" enumerada primero (tipo = "número"), particularmente en comparación con la "mejor" forma recomendada ($ parser en la directiva)?
Matt Welch
2
@MattWelch, respuesta tardía, pero la desventaja es la compatibilidad con el navegador. También en Chrome, al menos, type=numberse mostrará automáticamente la ruleta que puede ser indeseable. Puede ocultar la ruleta a través de css pero, de nuevo, incluso eso puede no funcionar en todos los navegadores.
Rosdi Kasim
4
Solo dos cosas que podrían ser problemáticas con el enfoque "fácil" (tipo = "número") son que 1. tipo = "número" permite el signo negativo (-), separador decimal (./,) y notación exponencial (e) y 2. en dispositivos móviles Samsung no puede ingresar un número negativo en un campo type = "number" (simplemente no hay una tecla menos en el teclado)
Aides
manera fácil ... Firefox permite introducir caracteres en un campo de solo número. No actualiza el modelo, pero muestra los caracteres
DRaehal
66

Usando ng-patternen el campo de texto:

<input type="text"  ng-model="myText" name="inputName" ng-pattern="onlyNumbers">

Luego incluye esto en tu controlador

$scope.onlyNumbers = /^\d+$/;
MarkJ
fuente
Esto es lo que terminé haciendo según la respuesta de Marks, ¡gracias por los ejemplos! ¡Estoy seguro de que ayudará a alguien!
Chris Bier
2
esto funciona casi a la perfección, pero aún permite ingresar 'e'.
Galletas
Realmente ayuda si está luchando con limitar el tipo = "número" y su longitud. La solución es usar este patrón ng y volver a type = "text". Solución muy ordenada y elimina una carga de verificación de código para ng-change o ng-keypress. Esta solución no permitía ingresar 'e's, así que supongo que es otro problema.
PeterS
1
Me parece que es específico del navegador en cuanto a si no permitirá ninguna entrada numérica o no. En Chrome, simplemente usar <input type = 'number' /> es suficiente y no permitirá ninguna entrada numérica, Firefox por otro lado con el mismo Html permitirá cualquier entrada pero activa la marca de entrada inválida si el valor no es numérico. Estoy buscando una forma sencilla de obtener el comportamiento de Chrome en todos los navegadores
Steve
19

Ninguna de las soluciones propuestas funcionó bien para mí, y después de un par de horas finalmente encontré el camino.

Esta es la directiva angular:

angular.module('app').directive('restrictTo', function() {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var re = RegExp(attrs.restrictTo);
            var exclude = /Backspace|Enter|Tab|Delete|Del|ArrowUp|Up|ArrowDown|Down|ArrowLeft|Left|ArrowRight|Right/;

            element[0].addEventListener('keydown', function(event) {
                if (!exclude.test(event.key) && !re.test(event.key)) {
                    event.preventDefault();
                }
            });
        }
    }
});

Y la entrada se vería así:

<input type="number" min="0" name="inputName" ng-model="myModel" restrict-to="[0-9]">

La expresión regular evalúa la tecla presionada, no el valor .

También funciona perfectamente con entradas type="number"porque evita que cambie su valor, por lo que la clave nunca se muestra y no ensucia el modelo.

ragnar
fuente
Para permitir que los negativos,restrict-to="[0-9\-]"
Noúmeno
18

Aquí está mi implementación de la $parsersolución que @Mark Rajcok recomienda como el mejor método. Es esencialmente el excelente analizador de $ de @ pkozlowski.opensource para la respuesta de texto, pero reescrito para permitir solo números. Todo el crédito es para él, esto es solo para ahorrarle los 5 minutos de leer esa respuesta y luego reescribir la suya:

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

            modelCtrl.$parsers.push(function (inputValue) {
                var transformedInput = inputValue ? inputValue.replace(/[^\d.-]/g,'') : null;

                if (transformedInput!=inputValue) {
                    modelCtrl.$setViewValue(transformedInput);
                    modelCtrl.$render();
                }

                return transformedInput;
            });
        }
    };
});

Y lo usarías así:

<input type="text" name="number" ng-model="num_things" numeric-only>

Curiosamente, los espacios nunca llegan al analizador a menos que estén rodeados por un alfanumérico, por lo que tendrá que hacerlo .trim()según sea necesario. Además, este analizador NO funciona <input type="number">. Por alguna razón, los no numéricos nunca llegan al analizador donde se eliminarían, pero sí lo hacen en el control de entrada.

Mordred
fuente
Cuando implementé esto, obtuve errores JS si el modelo de entrada se inicializó sin un valor. Al hacer este cambio se resolvió que: var transformedInput = inputValue ? inputValue.replace(/[^\d.-]/g,'') : null;
Alkie
Gracias @Alkie. Agregué ese cambio a la directiva.
Mordred
1
Debe configurarlo ng-trimpara falseasegurarse de que los espacios lleguen a su analizador.
Ilya
Para hacerlo perfecto, debe agregar modelCtrl.$commitViewValue();entre $ setViewValue (clean); y $ render ();
ingaham
1
¡Gracias! ¡Esto es simplemente increíble! Ayudó mucho
iulial
4

Hay varias formas de hacer esto.

Podrías usar type="number":

<input type="number" />

Alternativamente, creé una directiva reutilizable para esto que usa una expresión regular.

HTML

<div ng-app="myawesomeapp">
    test: <input restrict-input="^[0-9-]*$" maxlength="20" type="text" class="test" />
</div>

Javascript

;(function(){
    var app = angular.module('myawesomeapp',[])
    .directive('restrictInput', [function(){

        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                var ele = element[0];
                var regex = RegExp(attrs.restrictInput);
                var value = ele.value;

                ele.addEventListener('keyup',function(e){
                    if (regex.test(ele.value)){
                        value = ele.value;
                    }else{
                        ele.value = value;
                    }
                });
            }
        };
    }]);    
}());
Peter Rasmussen
fuente
use, $ (elemento) .on ('entrada', función () {// su lógica}); esto evitará incluso ingresar el valor no deseado
Vishal
4

Aquí hay una solución bastante buena para que solo permita ingresar un número al input:

<input type="text" ng-model="myText" name="inputName" onkeypress='return event.charCode >= 48 && event.charCode <= 57'/>
Raniys
fuente
esto no me permite presionar eliminar o retroceder
Ravistm
Sin embargo, eliminar y retroceder funciona. Probado en Firefox 76.0.1
iamjoshua
3

Todas las soluciones anteriores son bastante grandes, quería dar mis 2 centavos en esto.

Solo estoy verificando si el valor ingresado es un número o no, y si no está en blanco, eso es todo.

Aquí está el html:

<input type="text" ng-keypress="CheckNumber()"/>

Aquí está el JS:

$scope.CheckKey = function () {
    if (isNaN(event.key) || event.key === ' ' || event.key === '') {
        event.returnValue = '';
    }
};

Es muy sencillo.

Creo que esto no funcionará en Paste, solo para que se sepa.

Para Pegar, creo que necesitaría usar el evento onChange y analizar toda la cadena, otra bestia muy distinta a la del tamme. Esto es específico para escribir.

ACTUALIZAR para Pegar : solo agregue esta función JS:

$scope.CheckPaste = function () {
    var paste = event.clipboardData.getData('text');

    if (isNaN(paste)) {
        event.preventDefault();
        return false;
    }
};

Y la entrada html agrega el disparador:

<input type="text" ng-paste="CheckPaste()"/>

Espero que esto te ayude

Zorkind
fuente
2

Aquí hay un Plunker que maneja cualquier situación anterior a la propuesta que no maneja.
Utilizando $ formateadores y $ parsers pipeline y evitando type = "number"

Y aquí está la explicación de problemas / soluciones (también disponible en Plunker):

/*
 *
 * Limit input text for floating numbers.
 * It does not display characters and can limit the Float value to X numbers of integers and X numbers of decimals.
 * min and max attributes can be added. They can be Integers as well as Floating values.
 *
 * value needed    |    directive
 * ------------------------------------
 * 55              |    max-integer="2"
 * 55.55           |    max-integer="4" decimal="2" (decimals are substracted from total length. Same logic as database NUMBER type)
 *
 *
 * Input type="number" (HTML5)
 *
 * Browser compatibility for input type="number" :
 * Chrome : - if first letter is a String : allows everything
 *          - if first letter is a Integer : allows [0-9] and "." and "e" (exponential)
 * Firefox : allows everything
 * Internet Explorer : allows everything
 *
 * Why you should not use input type="number" :
 * When using input type="number" the $parser pipeline of ngModel controller won't be able to access NaN values.
 * For example : viewValue = '1e'  -> $parsers parameter value = "".
 * This is because undefined values are not allowes by default (which can be changed, but better not do it)
 * This makes it impossible to modify the view and model value; to get the view value, pop last character, apply to the view and return to the model.
 *
 * About the ngModel controller pipelines :
 * view value -> $parsers -> model value
 * model value -> $formatters -> view value
 *
 * About the $parsers pipeline :
 * It is an array of functions executed in ascending order.
 * When used with input type="number" :
 * This array has 2 default functions, one of them transforms the datatype of the value from String to Number.
 * To be able to change the value easier (substring), it is better to have access to a String rather than a Number.
 * To access a String, the custom function added to the $parsers pipeline should be unshifted rather than pushed.
 * Unshift gives the closest access to the view.
 *
 * About the $formatters pipeline :
 * It is executed in descending order
 * When used with input type="number"
 * Default function transforms the value datatype from Number to String.
 * To access a String, push to this pipeline. (push brings the function closest to the view value)
 *
 * The flow :
 * When changing ngModel where the directive stands : (In this case only the view has to be changed. $parsers returns the changed model)
 *     -When the value do not has to be modified :
 *     $parsers -> $render();
 *     -When the value has to be modified :
 *     $parsers(view value) --(does view needs to be changed?) -> $render();
 *       |                                  |
 *       |                     $setViewValue(changedViewValue)
 *       |                                  |
 *       --<-------<---------<--------<------
 *
 * When changing ngModel where the directive does not stand :
 *     - When the value does not has to be modified :
 *       -$formatters(model value)-->-- view value
 *     -When the value has to be changed
 *       -$formatters(model vale)-->--(does the value has to be modified) -- (when loop $parsers loop is finished, return modified value)-->view value
 *                                              |
 *                                  $setViewValue(notChangedValue) giving back the non changed value allows the $parsers handle the 'bad' value
 *                                               |                  and avoids it to think the value did not changed
 *                Changed the model <----(the above $parsers loop occurs)
 *
 */
gr3g
fuente
1
   <input type="text" name="profileChildCount" id="profileChildCount" ng-model="profile.ChildCount" numeric-only maxlength="1" />

puede utilizar un atributo solo numérico.

tahsin ilhan
fuente
1

DECIMAL

directive('decimal', 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 "";
                        }
                        ctrl.$parsers.push(inputValue);
                    }
                };
            });

DIGITOS

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

                            if (digits !== value) {
                                ctrl.$setViewValue(digits);
                                ctrl.$render();
                            }
                            return parseInt(digits);
                        }
                        return "";
                    }
                    ctrl.$parsers.push(inputValue);
                }
            };
        });

directivas angulares para validar números

Angeldev
fuente
0

Sé que esto es antiguo, pero he creado una directiva para este propósito en caso de que alguien esté buscando una solución fácil. Muy simple de usar.

Puedes comprobarlo aquí .

cohenadair
fuente
0

es posible que también desee eliminar el 0 al comienzo de la entrada ... Simplemente agrego un bloque if a la respuesta de Mordred anterior porque todavía no puedo hacer un comentario ...

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

          modelCtrl.$parsers.push(function (inputValue) {
              var transformedInput = inputValue ? inputValue.replace(/[^\d.-]/g,'') : null;

              if (transformedInput!=inputValue) {
                  modelCtrl.$setViewValue(transformedInput);
                  modelCtrl.$render();
              }
              //clear beginning 0
              if(transformedInput == 0){
                modelCtrl.$setViewValue(null);
                modelCtrl.$render();
              }
              return transformedInput;
          });
      }
    };
  })
sireken
fuente
0

Prueba esto,

<input ng-keypress="validation($event)">

 function validation(event) {
    var theEvent = event || window.event;
    var key = theEvent.keyCode || theEvent.which;
    key = String.fromCharCode(key);
    var regex = /[0-9]|\./;
    if (!regex.test(key)) {
        theEvent.returnValue = false;
        if (theEvent.preventDefault) theEvent.preventDefault();
    }

}
Joee
fuente
0

SOLUCIÓN: hago una directiva para todas las entradas, número, texto o cualquiera, en la aplicación, para que pueda ingresar un valor y cambiar el evento. Hacer para angular 6

 import { Directive, ElementRef, HostListener, Input } from '@angular/core';

 @Directive({
// tslint:disable-next-line:directive-selector
selector: 'input[inputType]'
})
  export class InputTypeDirective {
 constructor(private _el: ElementRef) {}

 @Input() inputType: string;
 // tipos: number, letter, cuit, tel

@HostListener('input', ['$event']) onInputChange(event) {
if (!event.data) {
  return;
}

switch (this.inputType) {
  case 'number': {
    const initalValue = this._el.nativeElement.value;
    this._el.nativeElement.value = initalValue.replace(/[^0-9]*/g, '');
    if (initalValue !== this._el.nativeElement.value) {
      event.stopPropagation();
    }
     break;
          }
       case 'text': {
        const result = event.data.match(/[^a-zA-Z Ññ]*/g);
        if (result[0] !== '') {
           const initalValue = this._el.nativeElement.value;
           this._el.nativeElement.value = initalValue.replace(
          /[^a-zA-Z Ññ]*/g,
           ''
         );
           event.stopPropagation();
        }
        break;
    }
        case 'tel':
          case 'cuit': {
         const initalValue = this._el.nativeElement.value;
      this._el.nativeElement.value = initalValue.replace(/[^0-9-]*/g, '');
       if (initalValue !== this._el.nativeElement.value) {
         event.stopPropagation();
       }
     }
   }
  }
   }

HTML

     <input matInput inputType="number" [formControlName]="field.name" [maxlength]="field.length" [placeholder]="field.label | translate"  type="text" class="filter-input">
Seba Arce
fuente
-1

Terminé creando una directiva modificada del código anterior para aceptar la entrada y cambiar el formato sobre la marcha ...

.directive('numericOnly', function($filter) {
  return {
      require: 'ngModel',
      link: function(scope, element, attrs, modelCtrl) {

           element.bind('keyup', function (inputValue, e) {
             var strinput = modelCtrl.$$rawModelValue;
             //filter user input
             var transformedInput = strinput ? strinput.replace(/[^,\d.-]/g,'') : null;
             //remove trailing 0
             if(transformedInput.charAt(0) <= '0'){
               transformedInput = null;
               modelCtrl.$setViewValue(transformedInput);
               modelCtrl.$render();
             }else{
               var decimalSplit = transformedInput.split(".")
               var intPart = decimalSplit[0];
               var decPart = decimalSplit[1];
               //remove previously formated number
               intPart = intPart.replace(/,/g, "");
               //split whole number into array of 3 digits
               if(intPart.length > 3){
                 var intDiv = Math.floor(intPart.length / 3);
                 var strfraction = [];
                 var i = intDiv,
                     j = 3;

                 while(intDiv > 0){
                   strfraction[intDiv] = intPart.slice(intPart.length-j,intPart.length - (j - 3));
                   j=j+3;
                   intDiv--;
                 }
                 var k = j-3;
                 if((intPart.length-k) > 0){
                   strfraction[0] = intPart.slice(0,intPart.length-k);
                 }
               }
               //join arrays
               if(strfraction == undefined){ return;}
                 var currencyformat = strfraction.join(',');
                 //check for leading comma
                 if(currencyformat.charAt(0)==','){
                   currencyformat = currencyformat.slice(1);
                 }

                 if(decPart ==  undefined){
                   modelCtrl.$setViewValue(currencyformat);
                   modelCtrl.$render();
                   return;
                 }else{
                   currencyformat = currencyformat + "." + decPart.slice(0,2);
                   modelCtrl.$setViewValue(currencyformat);
                   modelCtrl.$render();
                 }
             }
            });
      }
  };

})

sireken
fuente
-1
<input type="text" ng-model="employee.age" valid-input input-pattern="[^0-9]+" placeholder="Enter an age" />

<script>
var app = angular.module('app', []);

app.controller('dataCtrl', function($scope) {
});

app.directive('validInput', function() {
  return {
    require: '?ngModel',
    scope: {
      "inputPattern": '@'
    },
    link: function(scope, element, attrs, ngModelCtrl) {

      var regexp = null;

      if (scope.inputPattern !== undefined) {
        regexp = new RegExp(scope.inputPattern, "g");
      }

      if(!ngModelCtrl) {
        return;
      }

      ngModelCtrl.$parsers.push(function(val) {
        if (regexp) {
          var clean = val.replace(regexp, '');
          if (val !== clean) {
            ngModelCtrl.$setViewValue(clean);
            ngModelCtrl.$render();
          }
          return clean;
        }
        else {
          return val;
        }

      });

      element.bind('keypress', function(event) {
        if(event.keyCode === 32) {
          event.preventDefault();
        }
      });
    }
}}); </script>
Rahul Sharma
fuente
1
El dumping de códigos generalmente está mal visto. Por favor agregue alguna explicación.
rayryeng
1
para restringir la pulsación de la tecla, intente esto - - - Número de función (evt) {var charCode = (evt.which)? evt.which: event.keyCode if (charCode> 31 && (charCode <48 || charCode> 57)) return false; devuelve verdadero; <input type = "number" min = "0" onkeypress = "return Number (event)">
Rahul Sharma
-1

HTML básico

<input type="number" />

Bootstrap básico

<input class="form-control" type="number" value="42" id="my-id">
Amr Ibrahim
fuente
@Praveen, no estoy de acuerdo contigo, la pregunta no menciona ningún arranque. ¿Por qué deberíamos mencionar que algo no existe en la pregunta?
Amr Ibrahim
si queremos usar bootstrap <input class="form-control" type="number" >
Amr Ibrahim