Как разрешить ввод только числа (цифры и десятичная точка) на входе?

Я новичок в angularjs. Мне интересно, каким образом можно разрешить только допустимое число, введенное в текстовое поле. Например, пользователь может ввести "1.25", но не может ввести "1.a" или "1..". Когда пользователь пытается ввести следующий символ, который сделает его недопустимым, он не может ввести его.

Спасибо заранее.

Ответ 1

Вы можете попробовать эту директиву, чтобы остановить ввод недопустимых символов в поле ввода. ( Обновление: это зависит от директивы, имеющей явное знание модели, которая не является идеальной для повторного использования, см. ниже для примера повторного использования)

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

Он также учитывает следующие сценарии:

  • Переход от непустой допустимой строки к пустой строке
  • Отрицательные значения
  • Отрицательные десятичные значения

Я создал jsFiddle, чтобы вы могли видеть, как это работает.

UPDATE

После отзыва Адама Томаса о том, что ссылки не включены в директиву напрямую (я также считаю, что это лучший подход), я обновил jsFiddle, чтобы предоставить метод, который не полагается на это.

В директиве используется двунаправленная привязка локальной области действия к родительской области. Изменения, внесенные в переменные внутри директивы, будут отображаться в родительской области и наоборот.

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>

Angular код:

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

Ответ 2

Я написал рабочий пример CodePen, чтобы продемонстрировать отличный способ фильтрации числового ввода пользователем. В настоящее время директива допускает только положительные целые числа, но регулярное выражение может быть легко обновлено для поддержки любого нужного числового формата.

Моя директива проста в использовании:

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

Директива очень легко понять:

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

Я хочу подчеркнуть, что важно сохранять ссылки на модель из директивы.

Надеюсь, вы сочтете это полезным.

Большое спасибо Шона Криста и Криса Граймса за представление меня ngModelController

Ответ 3

Прежде всего большое спасибо Адам Томас Для этого я использовал ту же логику Адама с небольшой модификацией, чтобы принимать десятичные значения.

Примечание. Это позволит использовать цифры только с двумя десятичными знаками

Вот мой Рабочий пример

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

Ответ 4

Используйте тег шага, чтобы установить минимальное изменяемое значение для некоторого десятичного числа:

например. шаг = "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>

Здесь есть документация:

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

Ответ 5

DEMO - - jsFiddle

Директива

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

Примечание. Не забудьте включить jQuery с angular js

Ответ 6

Существует директива числового ввода, которую я верю, могу сделать именно то, что вы хотите.

<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}"]>

официальный документ находится здесь: http://docs.angularjs.org/api/ng.directive:input.number

Ответ 7

Вы можете легко использовать ng-шаблон.

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

Ответ 8

HTML

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

//Просто введите 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 или 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);
      }
    };

Ответ 9

Мне нужна директива, которая может быть ограничена в диапазоне атрибутами min и max следующим образом:

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

поэтому я написал следующее:

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

Ответ 10

Вот мой действительно быстрый n-грязный:

<!-- 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 = {};
});

Для этого необходимо включить библиотеку angular -resource для постоянных привязок к полям для целей проверки.

Рабочий пример здесь

Работает как чемпион в 1.2.0-rc.3+. Измените регулярное выражение, и вы должны быть настроены. Возможно, что-то вроде /^(\d|\.)+$/? Как всегда, подтвердите серверную сторону, когда закончите.

Ответ 11

Это кажется мне самым легким: http://jsfiddle.net/thomporter/DwKZh/

(Код не мой, я случайно наткнулся на него)

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

Ответ 12

Я изменил ответ Алана выше, чтобы ограничить число указанным min/max. Если вы вводите число за пределами диапазона, оно устанавливает минимальное или максимальное значение после 1500 мс. Если вы полностью очистите поле, оно ничего не установит.

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

Ответ 13

У меня была аналогичная проблема и обновил пример input[type="number"] в angular docs для работы с точностью до десятичных знаков, и я использую этот подход для его решения.

PS: Быстрое напоминание о том, что браузеры поддерживают символы "e" и "E" на входе [type = "number" ], потому что требуется событие keypress.

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

И в вашем html вы можете использовать этот подход

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

Вот плункер с этим фрагментом

Ответ 14

Расширяясь от ответа gordy:

Хорошая работа. Но это также позволило + спереди. Это удалит его.

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

Ответ 15

Вот производная, которая также будет блокировать десятичную точку, которую нужно ввести дважды

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(/[[email protected]#$%^&*()_+\-=\[\]{};':"\\|,<>\/?]/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;
        });
    }
};
});

Ответ 16

Расширение ответа Адама Томаса позволяет легко сделать эту директиву более общей, добавив входной аргумент с пользовательским регулярным выражением:

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>

Live on CodePen

Ответ 17

Пожалуйста, проверьте мой компонент, который поможет вам разрешить только определенный тип данных. В настоящее время поддерживаются целочисленные, десятичные, строковые и временные (HH: MM).

  • string - строка допускается с дополнительной максимальной длиной
  • integer - Целое число допускается только с дополнительным максимальным значением
  • decimal - Десятичное значение разрешено только с необязательными десятичными точками и максимальным значением (по умолчанию 2 десятичной точки)
  • time - 24 hr Формат времени (HH: MM) разрешен только

https://github.com/ksnimmy/txDataType

Надеюсь, что это поможет.

Ответ 18

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

ЦИФРЫ

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

angular директивы для проверки номеров

Ответ 19

Когда у меня есть два ввода, как один текст, а другой номер. В Firefox, в самый первый раз это позволяет вводить алфавиты при вводе чисел, если я приду от ввода текста к вводу чисел. Можете ли вы дать мне знать, как решить эту проблему?

Пожалуйста, смотрите прикрепленный снимок экрана для получения дополнительной информации. enter image description here Спасибо, Анант