Pregunta ¿Cómo restrinjo una entrada para solo aceptar números?


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 tengo que apuntar a la entrada que se activó numbersOnly() para que pueda eliminar las letras ingresadas. He buscado mucho en Google y no he podido encontrar nada al respecto.

¿Que puedo hacer?


73
2018-01-30 22:38


origen


Respuestas:


Camino fácil, utilizar tipo = "número" si funciona para tu caso de uso:

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

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

Hackish? camino, $ mira el modelo ng en tu 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
   }
})

Mejor manera, usa un $ parser en una directiva. No voy a repetir la 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, que hacen que encontrar this innecesario.

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


92
2018-01-30 23:51



Utilizando ng-pattern en el campo de texto:

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

Luego incluye esto en tu controlador

$scope.onlyNumbers = /^\d+$/;

64
2018-02-28 07:23



Aquí está mi implementación de la $parser solución que @Mark Rajcok recomienda como el mejor método. Es esencialmente @ pkozlowski.opensource's excelente $ parser para respuesta de texto pero reescrito para permitir solo números. Todo el mérito recae en él, esto es solo para ahorrarle los 5 minutos de leer esa respuesta y luego volver a escribir 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ías que .trim() según sea necesario. Además, este analizador hace NO trabajar en <input type="number">. Por alguna razón, los elementos no numéricos nunca llegan al analizador donde serían eliminados, pero hacer convertirlo en el control de entrada en sí.


16
2017-11-20 21:54



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 las entradas type="number" porque impide cambiar su valor, por lo que la clave nunca se muestra y no se mezcla con el modelo.


14
2017-11-17 13:26



Hay algunas maneras de hacer esto.

Podrías usar type="number":

<input type="number" />

Alternativamente, creé un reutilizable directiva 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;
                    }
                });
            }
        };
    }]);    
}());

4
2017-10-29 13:41



Aquí hay un Plunker manejando cualquier situación arriba de la proposición no maneje.
Utilizando $ formateadores y $ analizadores de canalización 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)
 *
 */

2
2018-02-05 10:59



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);
                    }
                };
            });

DÍGITOS

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


1
2018-01-06 17:07