Comment limiter une entrée pour n'accepter que des nombres?

92

J'utilise ngChange dans AngularJS pour déclencher une fonction personnalisée qui supprimera toutes les lettres que l'utilisateur ajoute à l'entrée.

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

Le problème est que je dois cibler l'entrée qui s'est déclenchée numbersOnly()afin de pouvoir supprimer les lettres entrées. J'ai cherché longuement et attentivement sur Google et je n'ai rien trouvé à ce sujet.

Que puis-je faire?

Chris Bier
la source
C'est aussi une bonne solution, qui ne permet pas de saisir des lettres.
Himanshu Bhandari
La duplication possible de la saisie de texte HTML autorise uniquement la saisie numérique
Shobhit Srivastava

Réponses:

104

Facile , utilisez type = "number" si cela fonctionne pour votre cas d'utilisation:

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

Un autre moyen simple: ng-pattern peut également être utilisé pour définir une regex qui limitera ce qui est autorisé dans le champ. Voir aussi la page "livre de recettes" sur les formulaires .

Hackish? façon , $ regardez le ng-model dans votre contrôleur:

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

Manette:

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

La meilleure façon , utilisez un analyseur $ dans une directive. Je ne vais pas répéter la déjà bonne réponse fournie par @ pkozlowski.opensource, alors voici le lien: https://stackoverflow.com/a/14425022/215945

Toutes les solutions ci-dessus impliquent l'utilisation de ng-model, ce qui rend la recherche thisinutile.

L'utilisation de ng-change posera des problèmes. Voir AngularJS - la réinitialisation de $ scope.value ne change pas la valeur dans le modèle (comportement aléatoire)

Mark Rajcok
la source
J'ai fini par créer une directive! Merci d'avoir inclus le meilleur moyen. J'ai fait un peu de recherche mais j'ai beaucoup appris!
Chris Bier
1
N'importe qui est-il capable de développer les inconvénients de la manière "facile" listée en premier (type = "nombre"), en particulier par rapport à la "meilleure" manière recommandée ($ parser dans la directive)?
Matt Welch le
2
@MattWelch, réponse tardive mais l'inconvénient est la prise en charge du navigateur. Toujours dans Chrome au moins, type=numberaffichera automatiquement le spinner, ce qui peut être indésirable. Vous pouvez masquer le spinner via css, mais encore une fois, même cela peut ne pas fonctionner sur tous les navigateurs.
Rosdi Kasim le
4
Deux choses qui pourraient poser problème avec l'approche "facile" (type = "nombre") sont que 1. type = "nombre" autorise le signe négatif (-), le séparateur décimal (./,) et la notation exponentielle (e) et 2. sur les appareils mobiles Samsung, vous ne pouvez pas entrer de nombre négatif dans un champ type = "number" (il n'y a tout simplement pas de touche moins sur le clavier)
Aides
moyen simple ... Firefox permet de saisir des caractères dans un champ numérique uniquement. Il ne met pas à jour le modèle, mais affiche les caractères
DRaehal
66

Utilisation ng-patternsur le champ de texte:

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

Ensuite, incluez-le sur votre manette

$scope.onlyNumbers = /^\d+$/;
MarkJ
la source
C'est ce que j'ai fini par faire sur la base de la réponse de Marks, merci pour les exemples! Je suis sûr que cela aidera quelqu'un!
Chris Bier
2
cela fonctionne presque parfaitement, mais permet toujours de saisir «e».
cookies le
Cela aide vraiment si vous avez du mal à limiter type = "number" et sa longueur. La solution est d'utiliser ce ng-pattern et de revenir à type = "text". Solution très soignée et supprime une charge de vérification de code pour ng-change ou ng-keypress. Cette solution ne permettait pas de saisir les e, je suppose donc que c'est un autre problème.
PeterS
1
Il me semble être spécifique au navigateur pour savoir s'il n'autorisera aucune entrée numérique ou non. Sur Chrome, il suffit d'utiliser <input type = 'number' /> et il n'autorisera aucune entrée numérique, Firefox par contre avec le même Html autorisera n'importe quelle entrée mais déclenchera l'indicateur d'entrée invalide si la valeur n'est pas numérique. Je recherche un moyen simple d'obtenir le comportement de Chrome sur tous les navigateurs
Steve
19

Aucune des solutions proposées ne fonctionnait bien pour moi, et après quelques heures, j'ai finalement trouvé le chemin.

C'est la directive angulaire:

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

Et l'entrée ressemblerait à:

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

L'expression régulière évalue la touche enfoncée, pas la valeur .

Il fonctionne également parfaitement avec les entrées type="number"car empêche de changer sa valeur, donc la clé n'est jamais affichée et elle ne gâche pas le modèle.

Ragnar
la source
Pour autoriser les négatifs,restrict-to="[0-9\-]"
Noumenon le
18

Voici ma mise en œuvre de la $parsersolution que @Mark Rajcok recommande comme la meilleure méthode. C'est essentiellement l' excellent analyseur $ de @ pkozlowski.opensource pour la réponse textuelle, mais réécrit pour n'autoriser que les chiffres. Tout le mérite lui revient, c'est juste pour vous épargner les 5 minutes de lecture de cette réponse puis de réécrire la vôtre:

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

Et vous l'utiliseriez comme ceci:

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

Fait intéressant, les espaces n'atteignent jamais l'analyseur syntaxique à moins d'être entourés d'un alphanumérique, vous devrez donc le faire .trim()si nécessaire. En outre, cet analyseur ne fonctionne PAS<input type="number"> . Pour une raison quelconque, les non-numériques ne parviennent jamais à l'analyseur où ils seraient supprimés, mais ils le font dans le contrôle d'entrée lui-même.

Mordred
la source
Quand j'ai implémenté cela, j'ai eu des erreurs JS si le modèle de l'entrée était initialisé sans valeur. Faire ce changement a résolu que: var transformedInput = inputValue ? inputValue.replace(/[^\d.-]/g,'') : null;
Alkie
Merci @Alkie. J'ai ajouté ce changement dans la directive.
Mordred
1
Vous devez définir ng-trimsur falsepour vous assurer que les espaces atteignent votre analyseur.
Ilya
Pour le rendre parfait, vous devez ajouter modelCtrl.$commitViewValue();entre le $ setViewValue (clean); et $ render ();
ingaham
1
Je vous remercie! C'est tout simplement génial! Cela a beaucoup aidé
iulial
4

Il y a quelques façons de le faire.

Vous pouvez utiliser type="number":

<input type="number" />

Alternativement - J'ai créé une directive réutilisable pour cela qui utilise une expression régulière.

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
la source
use, $ (element) .on ('input', function () {// votre logique}); cela empêchera même d'entrer la valeur indésirable
Vishal
4

Voici une très bonne solution pour ne permettre que d'entrer un numéro dans input:

<input type="text" ng-model="myText" name="inputName" onkeypress='return event.charCode >= 48 && event.charCode <= 57'/>
Raniys
la source
cela ne me permet pas d'appuyer sur la suppression ou le retour arrière
Ravistm
la suppression et le retour arrière fonctionnent cependant. Testé sur Firefox 76.0.1
iamjoshua
3

Toutes les solutions ci-dessus sont assez importantes, je voulais donner mes 2 cents à ce sujet.

Je vérifie seulement si la valeur saisie est un nombre ou non, et vérifie si elle n'est pas vide, c'est tout.

Voici le html:

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

Voici le JS:

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

C'est assez simple.

Je crois que cela ne fonctionnera pas sur Paste tho, juste pour qu'il soit connu.

Pour Paste, je pense que vous auriez besoin d'utiliser l'événement onChange et d'analyser toute la chaîne, une autre bête, le tamme. Ceci est spécifique à la saisie.

UPDATE for Paste : ajoutez simplement cette fonction JS:

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

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

Et l'entrée html ajoute le déclencheur:

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

J'espère que cela aide o /

Zorkind
la source
2

Voici un Plunker qui gère toute situation ci-dessus que la proposition ne gère pas.
En utilisant $ formatters et $ parsers pipeline et en évitant type = "number"

Et voici l'explication des problèmes / solutions (également disponible dans le 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
la source
1
   <input type="text" name="profileChildCount" id="profileChildCount" ng-model="profile.ChildCount" numeric-only maxlength="1" />

vous pouvez utiliser un attribut numérique uniquement.

tahsin ilhan
la source
1

DÉCIMAL

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

CHIFFRES

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

directives angulaires pour valider les nombres

Angeldev
la source
0

Je sais que c'est vieux, mais j'ai créé une directive à cet effet au cas où quelqu'un chercherait une solution simple. Très simple à utiliser.

Vous pouvez le vérifier ici .

cohenadair
la source
0

vous pouvez également supprimer le 0 au début de l'entrée ... J'ajoute simplement un bloc if à la réponse Mordred ci-dessus car je ne peux pas encore faire de commentaire ...

  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
la source
0

Essaye ça,

<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
la source
0

SOLUTION: je crée une directive pour toutes les entrées, nombre, texte ou autre, dans l'application, afin que vous puissiez saisir une valeur et modifier l'événement. Faire pour angulaire 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
la source
-1

J'ai fini par créer une directive modifiée du code ci-dessus pour accepter l'entrée et changer le format à la volée ...

.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
la source
-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
la source
1
Le dumping de code est généralement mal vu. Veuillez ajouter quelques explications.
rayryeng
1
pour restreindre la pression de la touche essayez ceci - - - function Number (evt) {var charCode = (evt.which)? evt.which: event.keyCode if (charCode> 31 && (charCode <48 || charCode> 57)) return false; retourne vrai; <input type = "number" min = "0" onkeypress = "return Number (event)">
Rahul Sharma
-1

HTML de base

<input type="number" />

Bootstrap de base

<input class="form-control" type="number" value="42" id="my-id">
Amr Ibrahim
la source
@Praveen je ne suis pas d'accord avec vous, la question ne mentionne aucun bootstrap. pourquoi nous devrions mentionner que quelque chose n'existe pas dans la question?
Amr Ibrahim le
si nous voulons utiliser bootstrap <input class="form-control" type="number" >
Amr Ibrahim