web-dev-qa-db-fra.com

Comment permettre uniquement à un nombre (chiffres et point décimal) d'être saisi dans une entrée?

Je suis nouveau à angularjs. Je me demande quel est le moyen de n'autoriser qu'un nombre valide saisi dans une zone de texte. Par exemple, l'utilisateur peut taper "1.25", mais pas "1.a" ou "1 ..". Lorsque l'utilisateur essaie de saisir le caractère suivant, ce qui le rendra invalide, il ne peut pas le saisir.

Merci d'avance.

57
user1669811

Vous pouvez essayer cette directive pour empêcher la saisie de tout caractère non valide dans un champ de saisie. ( Update : cela dépend de la directive ayant une connaissance explicite du modèle, ce qui n'est pas idéal pour une réutilisation, voir ci-dessous pour un exemple réutilisable.

app.directive('isNumber', function () {
    return {
        require: 'ngModel',
        link: function (scope) {    
            scope.$watch('wks.number', 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;
                }
            });
        }
    };
});

Il rend également compte de ces scénarios:

  1. Passer d'une chaîne valide non vide à une chaîne vide
  2. Valeurs négatives
  3. Valeurs décimales négatives

J'ai créé un jsFiddle ici pour que vous puissiez voir comment cela fonctionne.

UPDATE

Suite aux commentaires d'Adam Thomas concernant l'inclusion des références de modèle directement dans une directive (que je crois également être la meilleure approche), j'ai mis à jour mon jsFiddle afin de fournir une méthode qui ne repose pas sur cela.

La directive utilise la liaison bidirectionnelle de la portée locale à la portée parente. Les modifications apportées aux variables à l'intérieur de la directive seront reflétées dans la portée parente et inversement.

HTML:

<form ng-app="myapp" name="myform" novalidate> 
    <div ng-controller="Ctrl">
        <number-only-input input-value="wks.number" input-name="wks.name"/>
    </div>
</form>

Code angulaire:

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

app.controller('Ctrl', function($scope) {
    $scope.wks =  {number: 1, name: 'testing'};
});
app.directive('numberOnlyInput', function () {
    return {
        restrict: 'EA',
        template: '<input name="{{inputName}}" ng-model="inputValue" />',
        scope: {
            inputValue: '=',
            inputName: '='
        },
        link: function (scope) {
            scope.$watch('inputValue', 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.inputValue = oldValue;
                }
            });
        }
    };
});
52
GordyD

J'ai écrit un exemple de travail avec CodePen pour montrer un excellent moyen de filtrer les entrées numériques de l'utilisateur. La directive n'autorise actuellement que les entiers positifs, mais l'expression rationnelle peut facilement être mise à jour pour prendre en charge le format numérique souhaité.

Ma directive est facile à utiliser:

<input type="text" ng-model="employee.age" valid-number />

La directive est très facile à comprendre:

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

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

app.directive('validNumber', function() {
  return {
    require: '?ngModel',
    link: function(scope, element, attrs, ngModelCtrl) {
      if(!ngModelCtrl) {
        return; 
      }

      ngModelCtrl.$parsers.Push(function(val) {
        if (angular.isUndefined(val)) {
            var val = '';
        }
        var clean = val.replace( /[^0-9]+/g, '');
        if (val !== clean) {
          ngModelCtrl.$setViewValue(clean);
          ngModelCtrl.$render();
        }
        return clean;
      });

      element.bind('keypress', function(event) {
        if(event.keyCode === 32) {
          event.preventDefault();
        }
      });
    }
  };
});

Je tiens à souligner que il est important de garder les références de modèle en dehors de la directive.

J'espère que ça t'as aidé.

Un grand merci à Sean Christe et à Chris Grimes de m'avoir présenté le ngModelController

104
Adam Thomas

Tout d’abord, merci beaucoup à Adam thomas J’ai utilisé la même logique d’Adam pour cela, avec une petite modification pour accepter les valeurs décimales.

Remarque: cela autorisera les chiffres avec seulement 2 valeurs décimales .

Voici mon exemple de travail

HTML

<input type="text" ng-model="salary" valid-number />

Javascript

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

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

    app.directive('validNumber', function() {
      return {
        require: '?ngModel',
        link: function(scope, element, attrs, ngModelCtrl) {
          if(!ngModelCtrl) {
            return; 
          }

          ngModelCtrl.$parsers.Push(function(val) {
            if (angular.isUndefined(val)) {
                var val = '';
            }
            var clean = val.replace(/[^0-9\.]/g, '');
            var decimalCheck = clean.split('.');

            if(!angular.isUndefined(decimalCheck[1])) {
                decimalCheck[1] = decimalCheck[1].slice(0,2);
                clean =decimalCheck[0] + '.' + decimalCheck[1];
            }

            if (val !== clean) {
              ngModelCtrl.$setViewValue(clean);
              ngModelCtrl.$render();
            }
            return clean;
          });

          element.bind('keypress', function(event) {
            if(event.keyCode === 32) {
              event.preventDefault();
            }
          });
        }
      };
    });
44
jamseernj

Utilisez la balise step pour définir la valeur modifiable minimale sur un nombre décimal:

par exemple. step = "0.01"

<input type="number" step="0.01" min="0" class="form-control" 
name="form_name" id="your_id" placeholder="Please Input a decimal number" required>

Il y a de la documentation à ce sujet ici:

http://blog.isotoma.com/2012/03/html5-input-typenumber-and-decimalsfloats-in-chrome/

DÉMO - - jsFiddle

Directive

   .directive('onlyNum', function() {
      return function(scope, element, attrs) {

         var keyCode = [8,9,37,39,48,49,50,51,52,53,54,55,56,57,96,97,98,99,100,101,102,103,104,105,110];
          element.bind("keydown", function(event) {
            console.log($.inArray(event.which,keyCode));
            if($.inArray(event.which,keyCode) == -1) {
                scope.$apply(function(){
                    scope.$eval(attrs.onlyNum);
                    event.preventDefault();
                });
                event.preventDefault();
            }

        });
     };
  });

HTML

 <input type="number" only-num>

Remarque: N'oubliez pas d'inclure jQuery avec angular js

7
Nishchit Dhanani

Vous pouvez facilement utiliser le motif ng.

ng-pattern="/^[1-9][0-9]{0,2}(?:,?[0-9]{3}){0,3}(?:\.[0-9]{1,2})?$/"
6
Afsal

Il y a une directive sur le nombre d'entrée que je crois pouvoir faire exactement ce que vous voulez.

<input type="number"
   ng-model="{string}"
   [name="{string}"]
   [min="{string}"]
   [max="{string}"]
   [required]
   [ng-required="{string}"]
   [ng-minlength="{number}"]
   [ng-maxlength="{number}"]
   [ng-pattern="{string}"]
   [ng-change="{string}"]>

le document officiel est ici: http://docs.angularjs.org/api/ng.directive:input.number

5
bingjie2680

HTML

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

// suffit de taper 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 ou 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 !== val) {
              ctrl.$setViewValue(digits);
              ctrl.$render();
            }
            return parseFloat(digits);
          }
          return undefined;
        }            
        ctrl.$parsers.Push(inputValue);
      }
    };
4
My Mai

Je voulais une directive dont la portée pouvait être limitée par les attributs min et max comme suit:

<input type="text" integer min="1" max="10" />

alors j'ai écrit ce qui suit:

.directive('integer', function() {
    return {
        restrict: 'A',
        require: '?ngModel',
        link: function(scope, elem, attr, ngModel) {
            if (!ngModel)
                return;

            function isValid(val) {
                if (val === "")
                    return true;

                var asInt = parseInt(val, 10);
                if (asInt === NaN || asInt.toString() !== val) {
                    return false;
                }

                var min = parseInt(attr.min);
                if (min !== NaN && asInt < min) {
                    return false;
                }

                var max = parseInt(attr.max);
                if (max !== NaN && max < asInt) {
                    return false;
                }

                return true;
            }

            var prev = scope.$eval(attr.ngModel);
            ngModel.$parsers.Push(function (val) {
                // short-circuit infinite loop
                if (val === prev)
                    return val;

                if (!isValid(val)) {
                    ngModel.$setViewValue(prev);
                    ngModel.$render();
                    return prev;
                }

                prev = val;
                return val;
            });
        }
    };
});
2
AlexFoxGill

J'ai eu un problème similaire et j'ai mis à jour l'exemple input[type="number"] sur angular docs pour les travaux avec une précision décimale et j'utilise cette approche pour le résoudre.

PS: Un rappel rapide est que les navigateurs prennent en charge les caractères 'e' et 'E' dans l'entrée [type = "numéro"], car l'événement keypress est requis. .

angular.module('numfmt-error-module', [])
.directive('numbersOnly', function() {
  return {
    require: 'ngModel',
    scope: {
      precision: '@'
    },
    link: function(scope, element, attrs, modelCtrl) {
      var currencyDigitPrecision = scope.precision;

      var currencyDigitLengthIsInvalid = function(inputValue) {
        return countDecimalLength(inputValue) > currencyDigitPrecision;
      };

      var parseNumber = function(inputValue) {
        if (!inputValue) return null;
        inputValue.toString().match(/-?(\d+|\d+.\d+|.\d+)([eE][-+]?\d+)?/g).join('');
        var precisionNumber = Math.round(inputValue.toString() * 100) % 100;

        if (!!currencyDigitPrecision && currencyDigitLengthIsInvalid(inputValue)) {
          inputValue = inputValue.toFixed(currencyDigitPrecision);
          modelCtrl.$viewValue = inputValue;
        }
        return inputValue;
      };

      var countDecimalLength = function (number) { 
         var str = '' + number;
         var index = str.indexOf('.');
         if (index >= 0) {
           return str.length - index - 1;
         } else {
           return 0;
         }
      };

      element.on('keypress', function(evt) {
        var charCode, isACommaEventKeycode, isADotEventKeycode, isANumberEventKeycode;
        charCode = String.fromCharCode(evt.which || event.keyCode);
        isANumberEventKeycode = '0123456789'.indexOf(charCode) !== -1;
        isACommaEventKeycode = charCode === ',';
        isADotEventKeycode = charCode === '.';

        var forceRenderComponent = false;

        if (modelCtrl.$viewValue != null && !!currencyDigitPrecision) {
          forceRenderComponent = currencyDigitLengthIsInvalid(modelCtrl.$viewValue);
        }

        var isAnAcceptedCase = isANumberEventKeycode || isACommaEventKeycode || isADotEventKeycode;

        if (!isAnAcceptedCase) {
          evt.preventDefault();
        }

        if (forceRenderComponent) {
          modelCtrl.$render(modelCtrl.$viewValue);
        }

        return isAnAcceptedCase;
      });

      modelCtrl.$render = function(inputValue) {
        return element.val(parseNumber(inputValue));
      };

      modelCtrl.$parsers.Push(function(inputValue) {

        if (!inputValue) {
          return inputValue;
        }

        var transformedInput;
        modelCtrl.$setValidity('number', true);
        transformedInput = parseNumber(inputValue);

        if (transformedInput !== inputValue) {

          modelCtrl.$viewValue = transformedInput;
          modelCtrl.$commitViewValue();
          modelCtrl.$render(transformedInput);
        }
        return transformedInput;
      });
    }
  };
});

Et dans votre HTML, vous pouvez utiliser cette approche

<input 
  type="number" 
  numbers-only 
  precision="2" 
  ng-model="model.value" 
  step="0.10" />

Voici le plunker avec cet extrait

1
Wilson Mendes

Voici mon très rapide-sale:

<!-- HTML file -->
<html ng-app="num">
  <head></head>
  <body ng-controller="numCtrl">
    <form class="digits" name="digits" ng-submit="getGrades()" novalidate >
      <input type="text" placeholder="digits here plz" name="nums" ng-model="nums" required ng-pattern="/^(\d)+$/" />
      <p class="alert" ng-show="digits.nums.$error.pattern">Numbers only, please.</p> 
      <br>
      <input type="text" placeholder="txt here plz" name="alpha" ng-model="alpha" required ng-pattern="/^(\D)+$/" />
      <p class="alert" ng-show="digits.alpha.$error.pattern">Text only, please.</p>
      <br>
      <input class="btn" type="submit" value="Do it!" ng-disabled="!digits.$valid" />
    </form>
  </body>
</html>

// Javascript file
var app = angular.module('num', ['ngResource']);
app.controller('numCtrl', function($scope, $http){
  $scope.digits = {};
});

Cela nécessite d'inclure la bibliothèque de ressources angulaires pour les liaisons persistantes aux champs à des fins de validation.

Exemple de travail ici

Fonctionne comme un champion dans 1.2.0-rc.3 +. Modifier la regex et vous devriez être tous ensemble. Peut-être quelque chose comme /^(\d|\.)+$/? Comme toujours, validez le côté serveur lorsque vous avez terminé.

1
Astockwell

J'ai modifié la réponse d'Alan ci-dessus pour limiter le nombre au min/max spécifié. Si vous entrez un nombre en dehors de la plage, la valeur minimale ou maximale sera définie après 1500 ms. Si vous effacez complètement le champ, rien ne sera défini.

HTML:

<input type="text" ng-model="employee.age" min="18" max="99" valid-number />

Javascript:

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

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

app.directive('validNumber', function($timeout) {
    return {
        require: '?ngModel',
        link: function(scope, element, attrs, ngModelCtrl) {
            if (!ngModelCtrl) {
                return;
            }

            var min = +attrs.min;
            var max = +attrs.max;
            var lastValue = null;
            var lastTimeout = null;
            var delay = 1500;

            ngModelCtrl.$parsers.Push(function(val) {
                if (angular.isUndefined(val)) {
                    val = '';
                }            

                if (lastTimeout) {
                    $timeout.cancel(lastTimeout);
                }

                if (!lastValue) {
                    lastValue = ngModelCtrl.$modelValue;
                }

                if (val.length) {
                    var value = +val;
                    var cleaned = val.replace( /[^0-9]+/g, ''); 

                    // This has no non-numeric characters
                    if (val.length === cleaned.length) {
                        var clean = +cleaned;

                        if (clean < min) {
                            clean = min;
                        } else if (clean > max) {
                            clean = max;
                        }

                        if (value !== clean || value !== lastValue) {
                            lastTimeout = $timeout(function () {
                                lastValue = clean;
                                ngModelCtrl.$setViewValue(clean);
                                ngModelCtrl.$render();
                            }, delay);
                        }
                    // This has non-numeric characters, filter them out
                    } else {
                        ngModelCtrl.$setViewValue(lastValue);
                        ngModelCtrl.$render();
                    }
                }

                return lastValue;
            });

            element.bind('keypress', function(event) {
                if (event.keyCode === 32) {
                    event.preventDefault();
                }
            });

            element.on('$destroy', function () {
                element.unbind('keypress');
            });
        }
    };
});
1
David Boyd

Celui-ci me semble le plus facile: http://jsfiddle.net/thomporter/DwKZh/

(Le code n'est pas le mien, je suis tombé par hasard dessus)

    angular.module('myApp', []).directive('numbersOnly', function(){
       return {
         require: 'ngModel',
         link: function(scope, element, attrs, modelCtrl) {
           modelCtrl.$parsers.Push(function (inputValue) {
               // this next if is necessary for when using ng-required on your input. 
               // In such cases, when a letter is typed first, this parser will be called
               // again, and the 2nd time, the value will be undefined
               if (inputValue == undefined) return '' 
               var transformedInput = inputValue.replace(/[^0-9]/g, ''); 
               if (transformedInput!=inputValue) {
                  modelCtrl.$setViewValue(transformedInput);
                  modelCtrl.$render();
               }         

               return transformedInput;         
           });
         }
       };
    });
1
David Votrubec

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

0
Angeldev

S'il vous plaît consulter mon composant qui vous aidera à autoriser uniquement un type de données particulier. Prise en charge des nombres entiers, décimaux, chaînes et heures (HH: MM).

  • string - La chaîne est autorisée avec une longueur maximale facultative
  • integer - Entier uniquement autorisé avec une valeur maximale facultative
  • decimal - Décimal uniquement autorisé avec des points décimaux optionnels et une valeur maximale (par défaut 2 points décimaux)
  • time - Format d'heure sur 24 h (HH: MM) uniquement autorisé

https://github.com/ksnimmy/txDataType

J'espère que ça t'as aidé.

0
Nimmy

Étendre la réponse de gordy:

Bon travail en passant. Mais cela permettait aussi de + à l'avant. Cela va l'enlever.

    scope.$watch('inputValue', 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.inputValue = oldValue;
        }
        if (arr.length > 0) {
            if (arr[0] === "+") {
                scope.inputValue = oldValue;
            }
        }
    });
0
ADL

Voici un dérivé qui bloquera également la virgule à entrer deux fois

HTML

    <input tabindex="1" type="text" placeholder="" name="salary" id="salary" data-ng-model="salary" numbers-only="numbers-only" required="required">

Angular

    var app = angular.module("myApp", []);

    app.directive('numbersOnly', function() {
    return {
            require : 'ngModel', link : function(scope, element, attrs,  modelCtrl) {
        modelCtrl.$parsers.Push(function(inputValue) {

            if (inputValue == undefined) {
                return ''; //If value is required
            }

            // Regular expression for everything but [.] and [1 - 10] (Replace all)
            var transformedInput = inputValue.replace(/[a-z!@#$%^&*()_+\-=\[\]{};':"\\|,<>\/?]/g, '');

            // Now to prevent duplicates of decimal point
            var arr = transformedInput.split('');

            count = 0; //decimal counter
            for ( var i = 0; i < arr.length; i++) {
                if (arr[i] == '.') {
                    count++; //  how many do we have? increment
                }
            }

            // if we have more than 1 decimal point, delete and leave only one at the end
            while (count > 1) {
                for ( var i = 0; i < arr.length; i++) {
                    if (arr[i] == '.') {
                        arr[i] = '';
                        count = 0;
                        break;
                    }
                }
            }

            // convert the array back to string by relacing the commas
            transformedInput = arr.toString().replace(/,/g, '');

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

            return transformedInput;
        });
    }
};
});
0
Thakhani Tharage

En étendant Adam Thomas answer, vous pouvez facilement rendre cette directive plus générique en ajoutant un argument d'entrée avec une expression rationnelle personnalisée:

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

app.controller('MainCtrl', 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();
        }
      });
    }
}});

HTML

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

En direct sur CodePen

0
Sergeev Andrew