AngularJS Restrict input to numbers does not work - javascript

I have an input box on my html page with gets databound to an ng-model. I use a directive to restrict the input field to numbers only. I cannot used the default HTML5 restrictions like type="number". The problem I have is that if a non digit char is entered twice, e.g to press 123 and then two times k, the k is added to 123 resulting in 123k. However when I press another key, the k gets removed by the directive.
Can someone help me out to fix the problem that the letter appears if you press the same key twice
The directive I use:
angular.module('app').
directive('onlyDigits', function () {
return {
restrict: 'A',
require: '?ngModel',
link: function (scope, element, attrs, ngModel) {
if (!ngModel) return;
ngModel.$parsers.unshift(function (inputValue) {
var digits = inputValue.split('').filter(function (s) { return (!isNaN(s) && s != ' '); }).join('');
ngModel.$viewValue = digits;
ngModel.$render();
return digits;
});
}
};
});

This is what we use to achieve numbers only in a directive:
directives.directive('numbersOnly', function () {
'use strict';
return {
require: 'ngModel',
link: function (scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function (inputValue) {
if (inputValue === undefined) {
return '';
}
var transformedInput = inputValue.replace(/[^0-9]/g, '');
if (transformedInput !== inputValue) {
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}
return transformedInput;
});
}
};
});

Related

Angular js allow alphabetical caharacters and special characters but not numbers

My directive is below. What i want is that to allow alphabetical caharacters and special characters but not numbers. How can we changed that based on my code below.Thank you.
app.directive('validEn', function () {
return {
require: '?ngModel',
link: function (scope, element, attrs, ngModelCtrl, SweetAlert) {
if (!ngModelCtrl) {
return;
}
ngModelCtrl.$parsers.push(function (val) {
var clean = val.replace(/[^a-z|^A-z|^\s]+/g, '');
console.log("sfdsfd")
if (val !== clean) {
ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$render();
}
return clean;
});
element.bind('keypress', function (event) {
if (event.keyCode === 32) {
event.preventDefault();
}
});
}
};
});
You need to change your regex statement so that it replaces any numerics with empty string, as such:
var clean = val.replace(/\d*/g, '');

Using an AngularJS directive, how do I bind to keyup event on input field and revert model to previous value if it fails a regular expression check?

Doing a quick POC in AngularJS to only allow specific input into a text box.
The goal is to check the value every time the user types a new character, if it fails the regular expression check, we need to either reject the character or roll it back to the previous value.
The way I see it, here are my 2 options:
1. Bind to keypress event, check what the new value would be against a regex, and return false if it fails, preventing the character from being accepted into the text box
2. Bind to keyup event, check what the new value is against a regex, and if it fails, revert it to the previous value
How can I accomplish this from my directive?
var currencyRegEx = /^\$?\-?([1-9]{1}[0-9]{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\-?\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\(\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))\)$/;
app.directive("currencyInput", function () {
return {
restrict: "A",
scope: {
},
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
$(element).bind('keypress', function (event) {
// TODO: Get what new value would be
var newValue = "...";
return currencyRegEx.test(newValue);
});
$(element).bind('keyup', function (event) {
var newValue = $(this).val();
if (!currencyRegEx.test(newValue)) {
// TODO: Revert to previous value
}
});
}
}
});
<input type="text" class="form-control" ng-model="item.paymentAmount" currency-input />
EDIT w/ SOLUTION
Here is the current solution we have in place in order to prevent non-digit input and rollback invalid currency value.
First, we created a new property "scope.prevValue" to hold the last valid value entered by the user. Then, on "keypress" we check to make sure the user typed a digit, comma, or period. Finally, on "keyup", we check the new value against the currency regex and rollback if needed.
var currencyRegEx = /^\$?\-?([1-9]{1}[0-9]{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\-?\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\(\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))\)$/;
var digitRegex = /^[0-9]*$/;
app.directive("currencyInput", function () {
return {
restrict: "A",
scope: {},
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
scope.prevValue = '';
$(element).on('keypress', function(event) {
var validAlphaChars = ['.', ','];
var enteredCharacter = String.fromCharCode(event.charCode != null ? event.charCode : event.keyCode);
if (validAlphaChars.indexOf(enteredCharacter) < 0 && !digitRegex.test(enteredCharacter)) {
return false;
}
});
$(element).on('keyup', function (event) {
var newValue = $(element).val();
if (newValue.length > 0 && !currencyRegEx.test(newValue)) {
$(element).val(scope.prevValue);
return false;
} else {
scope.prevValue = $(element).val();
}
});
}
});
EDIT w/ SOLUTION #2 (using Steve_at_IDV's approach on accepted answer)
var currencyRegEx = /^\$?\-?([1-9]{1}[0-9]{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\-?\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\(\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))\)$/;
app.directive("currencyInput", function () {
return {
restrict: "A",
scope: {},
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$parsers.push(function (value) {
if (value.length > 0 && value != '.' && !currencyRegEx.test(value)) {
var prevValue = ngModelCtrl.$modelValue;
ngModelCtrl.$setViewValue(prevValue)
ngModelCtrl.$render();
return prevValue;
}
return value;
});
}
}
});
This would be a good time to use ngModelCtrl.$parsers instead of binding to keypresses manually. Try something like this in your link function:
ngModelCtrl.$parsers.push( function (value) {
// do some validation logic...it fails
if (validationFails) {
var prevValue = ctrl.$modelValue;
ctrl.$setViewValue(prevValue); // set view
ctrl.$render(); // render view
return prevValue; // set model
}
// otherwise we're good!
return value;
} );
Here is a Plunker which demonstrates. The input field will reject a lowercase z from being entered.
See the $parsers section of https://docs.angularjs.org/api/ng/type/ngModel.NgModelController for more info.
Firstly, I think you shouldn't modify the input of the user. I personnaly find it bad on a UX point of view. It's better to indicate that the input is in an error state by bordering in red for example.
Secondly, there is a directive that can fit your need, ng-pattern.
<input type="text"
class="form-control"
ng-model="item.paymentAmount"
ng-pattern="currencyRegEx" />
Some similar questions :
Angularjs dynamic ng-pattern validation
How to only allow the numbers 0-5 in <input> fields with AngularJS?

angularjs Date Input only

I am trying to validate input for date (dd/mm/yyy) and then if it is not date don't allow to enter - such as strings or anything
Below is my code but not working - means allowing users to enter anything
angular.module('app')
.directive('onlyDates', function () {
return {
require: 'ngModel',
restrict: 'A',
link: function (scope, element, attr, ctrl) {
function inputValue(val) {
if (val) {
var reg = /^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g;
var res = reg.test(val);
if (!res) {
ctrl.$setViewValue(val);
ctrl.$render();
return NaN;
}
return val;
}
return undefined;
}
ctrl.$parsers.push(inputValue);
}
};
});
you could try using ng-change and some function that can check "as you type" that what you are entering matches your pattern, and if not, delete the last char entered.
<input type="text" ng-model="txtValue" ng-change="TextBoxChangedCheck()">
$scope.TextBoxChangedCheck = function () {
//// enter your text validation here
};

javascript + regular expression

I have a problem. I want to use a regular expression that let me introduce just numbers and "." (for decimals) on an input field, no letters and other special character.
I'm trying this:
option 1 => var restrict="[^\d+]"
option 2 => var restrict="[^\d+]"
iAttrs.restrict = ^(?![0-9]+([.]?[0-9]+))$
value.toLowerCase().replace(new RegExp(iAttrs.restrict, 'g'), '');
This regular expression is an angular directive
appModule.directive('restrict', function($parse) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, iElement, iAttrs, controller) {
scope.$watch(iAttrs.ngModel, function(value) {
if (!value) {
return;
}
value = value.toString();
$parse(iAttrs.ngModel).assign(scope, value.toLowerCase().replace(new RegExp(iAttrs.restrict, 'g'), ''));
});
}
}
});
It must remove the wrong characters written on the input. But the problem is
option 1 ==> don't let me write "." character
option 2 ==> don't let me write nothing (when I have a default value example: "300.21" that must appear on the input field ... after restrict directive finish, nothing is written on the input.
Can somebody help me?
Thanks
Updated based on comments:
As the case for decimal point is very particular, I created a new directive for that.
Directive Code:
angular.module("app",[]).directive('allowOnlyDecimal', function($parse) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, iElement, iAttrs, controller) {
// used to find out if more than one . is available
function nth_ocurrence(str, needle, nth) {
for (i=0;i<str.length;i++) {
if (str.charAt(i) == needle) {
if (!--nth) {
return i;
}
}
}
return false;
}
scope.$watch(iAttrs.ngModel, function(value) {
if (!value) {
return;
}
value = value.toString();
var temp = value.replace(/[^(\d\.)]/gi, '');
// this removes any special character and alphabets
if(nth_ocurrence(temp,".",2)) {
temp = temp.substr(0, nth_ocurrence(temp,".",2));
// removes if user enters more than one decimal point
}
scope[iAttrs.ngModel] = temp;
});
}
};
}).controller("MainController", function($scope) {
$scope.someInput = 100.400;
});
In your HTML:
<input type="text" ng-model="someInput" allow-only-decimal>
WORKING DEMO
OLD ANSWER:
This could be more generic approach which you can use for most of the restrict functionality using regex.
HTML :
<input type="text" ng-model="someInput" restrict="[^(\d\.)]">
JS:
angular.module("app",[]).directive('restrict', function($parse, $timeout) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, iElement, iAttrs, controller) {
scope.$watch(iAttrs.ngModel, function(value) {
if (!value) {
return;
}
value = value.toString();
$timeout(function() {
scope[iAttrs.ngModel] = value.replace(new RegExp(iAttrs.restrict,'gi'), '');
},10);
});
}
};
}).controller("MainController", function($scope) {
$scope.someInput = 100.400;
});
You can use a simple regex like this:
^\d+\.*\d*$
Working demo

Why is my directive messing up my validations?

I ripped this directive off from this SO question.
var directive = 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);
}
};
};
module.exports = directive;
I want to limit my input to only accept numbers, but now my other validators, like min and max, are not working. My input is now always in an error state. What part of this directive is effecting the validation lifecycle in angular?

Categories

Resources