Allow only comma separated numbers in input field using angular js - javascript

I am using angular js and below is my code which allows only numbers separated by comma.But regex which I used allows user to enter 1,,,2.
Is there any way so that I can restrict user to enter only one comma after each number?
Plunker - http://plnkr.co/edit/g1X9ldVuH4ZewAlumM1P?p=preview
function NumberValidator() {
return {
require: '?ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
if (!ngModelCtrl) {
return;
}
ngModelCtrl.$parsers.push(function(val) {
var clean = val.replace(/[^\d+(,\d+)*$]/g, '');
if (val !== clean) {
ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$render();
}
return clean;
});
element.bind('keypress', function(event) {
if (event.keyCode === 32) {
event.preventDefault();
}
});
}
};

Remove the clean part and replace the if condition with,
if (!/^\d+(?:,\d+)*$/.test(val)) {
This code would test whether the given value is in 1,2,3 or 1 or 3,4 formats or not.
Example:
console.log(!/^f+$/.test('ff'))
console.log(!/^f+$/.test('df'))
Think you want something like this,
str.replace(/[^\d,]|^,+|,+$|,+(?=,)/gm, '')
PLNKR

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

Angular directive: Allow just numbers

Here is a sample angular directive to prevent typing non-numeric keys (StackOverflow answer).
I want to write something like this fiddle to use the is-number directive in several inputs. Please consider that since I have various different directives in my inputs, I cannot use the same template as suggested in the update of mentioned answer above.
var $scope;
var app = angular.module('myapp', []);
app.controller('Ctrl', function($scope) {
$scope.myNnumber1 = 1;
$scope.myNnumber2 = 1;
});
app.directive('isNumber', function () {
return {
require: 'ngModel',
link: function (scope, element) {
scope.$watch(element.ngModel, function(newValue,oldValue) {
newValue = String(newValue);
newValue = newValue.replace('۰', '0').replace('۱', '1').replace('۲', '2').replace('۳', '3').replace('۴', '4').replace('۵', '5').replace('۶', '6').replace('۷', '7').replace('۸', '8').replace('۹', '9');
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)) {
element.ngModel = oldValue;
}
});
}
};
Update:
Please consider that I need to do some processes to convert non English numbers and so on. I created a new fiddle here based on the the Angular_10's answer. Now, every thing is fine except the cursor position while typing Persian numbers. When I type A Persian Number, it is replaced with English equivalent number, but the cursor suddenly jumps to the end.
OK ! Looking at your requirement I've took liberty and wrote more customised directive.
Here is the fiddle for the same
Problem
The example from which you referred and made changes to the given directive is causing the issue.
Your $scope variable names are wrong in HTML/JS ($scope.myNnumber1 = 1;
$scope.myNnumber2 = 1; in JS and in HTML it was ng-model="myNumber1")
You are accessing element ng-model and trying to modify it through directive which is bad practice and also the root cause for directive to not to work.As you are not changing the ng-model value but in turn modifying HTML element value which angular will not recognise.
More over using $watch in directive is not always preferable for performance sake.
Solution
app.directive('isNumber', function() {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, element, attr, ctrl) {
function inputValue(val) {
if (val) {
var numeric = val.replace(/[^- 0-9]/g, '');
if (numeric !== val) {
ctrl.$setViewValue(numeric );
ctrl.$render();
}
return numeric;
}
return undefined;
}
ctrl.$parsers.push(inputValue);
}
};
});
When controller communication is required from directive we can pass Controller as 4 param in the link function.From that Ctrl param we can modify/view things from controller scope.
Using some basic regex expression to find out what is the entered input and set it in the controller scope object view value.
ctrl.$setViewValue(numeric); //to set the value in the respective ngModdel
ctrl.$render(); //to display the changed value
More about $setViewValue
I finally used the below directive. This directive converts persian number and do not let no numbers to be typed in the text box. Special thanks to Angular_10. I awarded 50 bounties to him for his help.
app.directive('fixPersianAndNoNumberInput', function ($filter) {
return {
require: 'ngModel',
restrict: 'EA',
link: function (scope, element, attr, controller) {
function inputValue(val) {
if (val) {
let numeric = parseInt(String(val).replace('۰', '0').replace('۱', '1').replace('۲', '2').replace('۳', '3').replace('۴', '4').replace('۵', '5').replace('۶', '6').replace('۷', '7').replace('۸', '8').replace('۹', '9').replace(' ', '000').replace(/[^- 0-9]/g, ''));
if (numeric !== val) {
controller.$setViewValue(numeric);
controller.$render();
let value;
let updateOn, debounce;
if (controller.$options) {
if (controller.$options.getOption) {
updateOn = controller.$options.getOption('updateOn');
debounce = controller.$options.getOption('debounce');
} else {
updateOn = controller.$options.updateOn;
debounce = controller.$options.debounce;
}
}
if (updateOn === 'blur' || debounce) {
value = controller.$viewValue;
for (let i = controller.$parsers.length - 1; i >= 0; i--) {
value = controller.$parsers[i](value);
}
} else {
value = controller.$$rawModelValue;
}
for (let j = controller.$formatters.length - 1; j >= 0; j--) {
value = controller.$formatters[j](value);
}
controller.$viewValue = value;
controller.$render();
}
return numeric;
}
return undefined;
}
controller.$parsers.push(inputValue);
controller.$formatters.push((value) => {
if ([undefined, null, ''].indexOf(value) === -1) {
return $filter('currency')(value, '', 0);
}
return value;
});
}
};
});

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 Restrict input to numbers does not work

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

ngRequired and custom directive in angular

I can't seem to get the smart float directive found in the angular docs example working when used together with ngRequired.
You can confirm this by going to the angular docs page
https://docs.angularjs.org/guide/forms
Edit the plunker on the smart float example, and add ng-required="false".
Make sure to check that the validity of the entire form, not the individual control.
The form itself is always marked as invalid if there is no input on the control.
I am using version 1.3.0-rc3
In order to allow empty values for smartFloat directive you should use $validators for validity check of the float value in conjunction with $parsers. Also note that returning undefined (or not returning any value) from any of the parsers will mark the whole form is invalid.
Allow empty values
var FLOAT_REGEXP = /^\-?\d+((\.|\,)\d+)?$/;
app.directive('smartFloat', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
// Parse
ctrl.$parsers.unshift(function (viewValue) {
if (!viewValue) {
return ''; // <-- Don't return undefined, but empty string instead
} else if (FLOAT_REGEXP.test(viewValue)) {
return parseFloat(viewValue.replace(',', '.'));
}
});
// Validate
ctrl.$validators.float = function (viewValue) {
if (viewValue === '') {
ctrl.$setValidity('float', true); // <-- Handle empty value as valid
return true;
} else if (FLOAT_REGEXP.test(viewValue)) {
ctrl.$setValidity('float', true);
return true;
} else {
ctrl.$setValidity('float', false);
return false;
}
};
}
};
});
Live example see here.

Categories

Resources