¿Cómo permitir que solo se escriba un número (dígitos y punto decimal) en una entrada?

Soy nuevo en angularjs. Me pregunto cuál es la forma de permitir que solo se escriba un número válido en un cuadro de texto. Por ejemplo, el usuario puede escribir “1.25”, pero no puede escribir “1.a” o “1 ..”. Cuando el usuario intente escribir el siguiente carácter que lo convertirá en un número inválido, no podrá ingresarlo.

Gracias por adelantado.

Puede probar esta directiva para evitar que se ingresen caracteres inválidos en un campo de entrada. ( Actualización : esto depende de que la directiva tenga un conocimiento explícito del modelo, que no es ideal para la reutilización, ver a continuación un ejemplo reutilizable)

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

También representa estos escenarios:

  1. Pasar de una cadena válida no vacía a una cadena vacía
  2. Valores negativos
  3. Valores decimales negativos

He creado un jsFiddle aquí para que pueda ver cómo funciona.

ACTUALIZAR

Siguiendo los comentarios de Adam Thomas sobre no incluir referencias de modelo directamente dentro de una directiva (que también creo que es el mejor enfoque), he actualizado mi jsFiddle para proporcionar un método que no se base en esto.

La directiva utiliza el enlace bidireccional de ámbito local para el scope principal. Los cambios realizados en las variables dentro de la directiva se reflejarán en el scope principal, y viceversa.

HTML:

 

Código 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: '', 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; } }); } }; }); 

Escribí un ejemplo de CodePen en funcionamiento para demostrar una excelente forma de filtrar las entradas numéricas de los usuarios. La directiva actualmente solo permite números enteros positivos, pero la expresión regular se puede actualizar fácilmente para admitir cualquier formato numérico deseado.

Mi directiva es fácil de usar:

  

La directiva es muy fácil de entender:

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

Quiero enfatizar que es importante mantener las referencias modelo fuera de la directiva.

Espero que encuentres esto útil.

Muchas gracias a Sean Christe y Chris Grimes por presentarme al ngModelController

Antes que nada, muchas gracias a Adam Thomas . Usé la misma lógica de Adam para esto con una pequeña modificación para aceptar los valores decimales.

Nota: Esto permitirá dígitos con solo 2 valores decimales

Aquí está mi ejemplo de trabajo

HTML

  

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

Use la etiqueta de paso para establecer el valor mínimo modificable a algún número decimal:

por ejemplo, paso = “0.01”

  

Hay algo de documentación aquí:

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

DEMO – – jsFiddle

Directiva

  .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

   

Nota: No olvide incluir jQuery con js angulares

Hay una directiva de número de entrada que creo que puede hacer exactamente lo que quiera.

  

el documento oficial está aquí: http://docs.angularjs.org/api/ng.directive:input.number

Usted podría usar fácilmente el patrón ng.

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

HTML

   

// Simplemente escribe 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); } }; 

// tipo: 123 o 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); } }; 

Quería una directiva que pudiera estar limitada en rango por los atributos min y max así:

entonces escribí lo siguiente:

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

Aquí está mi realmente rápido y sucio:

     

Numbers only, please.


Text only, please.


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

Esto requiere que incluya la biblioteca de recursos angulares para enlaces permanentes a los campos con fines de validación.

Ejemplo de trabajo aquí

Funciona como un campeón en 1.2.0-rc.3 +. Modifique la expresión regular y debería estar todo listo. Tal vez algo así como /^(\d|\.)+$/ ? Como siempre, valide el lado del servidor cuando haya terminado.

Este me parece el más fácil: http://jsfiddle.net/thomporter/DwKZh/

(El código no es mío, accidentalmente lo encontré)

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

Modifiqué la respuesta de Alan anterior para restringir el número al mínimo / máximo especificado. Si ingresa un número fuera del rango, establecerá el valor mínimo o máximo después de 1500 ms. Si borra el campo por completo, no establecerá nada.

HTML:

  

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

Tuve un problema similar y actualicé el ejemplo de input[type="number"] en documentos angulares para trabajos con precisión de decimales y estoy usando este enfoque para resolverlo.

PD: Un recordatorio rápido es que los navegadores admiten los caracteres “e” y “E” en la entrada [type = “number”], porque se requiere el evento de 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; }); } }; }); 

Y en tu html puedes usar este enfoque

  

Aquí está el plunker con este fragmento

Ampliando desde la respuesta de gordy:

Buen trabajo por cierto. Pero también permitió + en el frente. Esto lo eliminará.

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

Aquí hay una derivada que también bloqueará el punto decimal para ser ingresado dos veces

HTML

   

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

Al ampliar la respuesta de Adam Thomas, puede hacer que esta directiva sea más genérica añadiendo argumentos de entrada con expresiones regulares personalizadas:

 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

   

En vivo en CodePen

Por favor revisa mi componente que te ayudará a permitir solo un tipo de datos en particular. Actualmente admite números enteros, decimales, cadenas y horas (HH: MM).

  • string – Cadena está permitida con longitud máxima opcional
  • integer – Entero solo permitido con valor máximo opcional
  • decimal – Solo se permite el decimal con decimales opcionales y valor máximo (por defecto 2 decimales)
  • time – 24 hr Formato de hora (HH: MM) solo permitido

https://github.com/ksnimmy/txDataType

Espero que ayude.

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