web-dev-qa-db-fra.com

Comment puis-je limiter une entrée à n'accepter que des nombres?

J'utilise ngChange dans AngularJS pour déclencher une fonction personnalisée qui supprimera 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 a déclenché numbersOnly() afin de pouvoir supprimer les lettres entrées. J'ai longuement cherché Google et n'ai rien trouvé à ce sujet.

Que puis-je faire?

80
Chris Bier

Méthode simple , utilisez type = "numéro" 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 expression rationnelle qui limitera ce qui est autorisé dans le champ. Voir aussi la page "livre de recettes" sur les formulaires .

Hackish? way , $ regardez le modèle ng 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
   }
})

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

Toutes les solutions ci-dessus impliquent l'utilisation du modèle ng, ce qui rend inutile la recherche de this.

Utiliser ng-change causera des problèmes. Voir AngularJS - la réinitialisation de $ scope.value ne change pas la valeur dans le template (comportement aléatoire)

96
Mark Rajcok

Utiliser ng-pattern sur le champ de texte:

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

Ensuite, incluez ceci sur votre contrôleur

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

Aucune des solutions proposées ne me convenait et au bout de deux heures, j'ai finalement trouvé le chemin.

Ceci est la directive 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();
                }
            });
        }
    }
});

Et l'entrée ressemblerait à ceci:

<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.

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

18
ragnar

Voici mon implémentation de la solution $parser que @Mark Rajcok recommande comme meilleure méthode. Il s'agit essentiellement de @ pkozlowski.opensource excellent analyseur syntaxique pour la réponse texte mais réécrit pour permettre uniquement les valeurs numériques. Tout le mérite lui revient, ceci est juste pour vous faire gagner les 5 minutes de lecture de cette réponse et de réécriture de 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 à moins d'être entourés d'un caractère alphanumérique. Vous devez donc .trim() au besoin. En outre, cet analyseur NE FONCTIONNE PAS SUR sur <input type="number">. Pour une raison quelconque, les éléments non numériques ne parviennent jamais à l'analyseur où ils seraient supprimés, mais ils font en font le contrôle d'entrée lui-même.

16
Mordred

Il y a quelques façons de le faire.

Vous pouvez utiliser type="number":

<input type="number" />

Sinon, j'ai créé une directive réutilisable directive 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;
                    }
                });
            }
        };
    }]);    
}());
4
Peter Rasmussen

Voici un Plunker traitant toute situation ci-dessus que la proposition ne gère pas.
En utilisant $ pipeline de formateurs et d'analyseurs syntaxiques et en évitant le 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)
 *
 */
2
gr3g

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

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

Voici le code 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 pense que cela ne marchera pas avec Paste tho, juste pour que ce soit connu.

Pour Coller, je pense que vous auriez besoin d’utiliser l’événement onChange et d’analyser toute la chaîne, ce qui est tout à fait différent du tamme. Ceci est spécifique pour la frappe.

PDATE 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 /

2
Zorkind

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 des nombres

1
Angeldev

Manière HTML simple et propre

<input type="number" />
0
Amr Ibrahim

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

Vous pouvez le vérifier ici .

0
cohenadair
   <input type="text" name="profileChildCount" id="profileChildCount" ng-model="profile.ChildCount" numeric-only maxlength="1" />

vous pouvez utiliser un attribut numérique uniquement.

0
tahsin ilhan

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

}
0
Joee

Voici une très bonne solution pour ne permettre que l’entrée du nombre à la input:

<input type="text" ng-model="myText" name="inputName" onkeypress='return event.charCode >= 48 && event.charCode <= 57'/>
0
Raniys

SOLUTION: Je crée une directive pour toutes les entrées, numéros, textes ou autres de l'application, afin que vous puissiez saisir une valeur et modifier l'événement. Faire pour 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">
0
Seba Arce

vous voudrez peut-être aussi 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;
          });
      }
    };
  })
0
sireken