Restrict input as numbers on input fields using AngularJS - angularjs

I am trying to restrict input as numbers on below fields
Postal Code:
<input type="text" id="zipCode1" name="zipCode1" size="4" maxlength="5" ng-model="zipCode1" ng-change="myNumbers(zipCode1)" />
<input type="text" id="zipCode2" name="zipCode2" size="3" maxlength="4" ng-model="zipCode2" ng-change="myNumbers(zipCode2)" />
it doesn't work with
$scope.myNumbers = function(fieldName){
var tN = fieldName.replace(/[^\d]/g, "");
if(tN != fieldName)
fieldName = tN
};
It works with below code but changing both the fields
$scope.$watch('myNumbers', function() {
var tN = $scope.myNumbers.replace(/[^\d]/g, "");
if(tN != $scope.myNumbers)
$scope.myNumbers = tN;
})
Need to change the value for the input field where user is typing and not both

Use the directive found here: https://stackoverflow.com/a/19675023/149060 instead of the ng-change function. Replicated here for easy reference:
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;
});
}
};
});

You could try adding to the inputs ng-pattern='/^\d{2}$/'

Here is a directive I've done to restrict the keys allowed.
angular.module('app').directive('restrictTo', function() {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var re = RegExp(attrs.restrictTo);
var exclude = /Backspace|Enter|Tab|Delete|Del|ArrowUp|Up|ArrowDown|Down|ArrowLeft|Left|ArrowRight|Right/;
element[0].addEventListener('keydown', function(event) {
if (!exclude.test(event.key) && !re.test(event.key)) {
event.preventDefault();
}
});
}
}
});
And the input would look like:
<input type="text" name="zipCode1" maxlength="5" ng-model="zipCode1" restrict-to="[0-9]">
The regular expression evaluates the pressed key, not the value.
It also works perfectly with inputs type="number" because prevents from changing its value, so the key is never displayed and it does not mess with the model.

Related

angularjs directive - capitalize

I have this code below working fine when a user is typing an input data. But my problem is when the data is from the database(auto filled) my directive is not working(capitalize the letter
). Is there a reason why its not working?.
But when using a class="text-uppercase" its working.
HTML
<input ng-model="profile.Name" type="text" placeholder="" maxlength="40" capitalize />
JS
app.directive('capitalize', function ($parse) {
return {
require: 'ngModel',
link: function (scope, element, attrs, modelCtrl) {
var capitalize = function (inputValue) {
if (inputValue === undefined) { inputValue = ''; }
var capitalized = inputValue.toUpperCase();
//for (var i = 0; i < capitalized.length; i++) {
// capitalized[i] = capitalized[i].charAt(0).toUpperCase() + capitalized[i].substring(1);
//}
if (capitalized !== inputValue) {
modelCtrl.$setViewValue(capitalized);
modelCtrl.$render();
}
return capitalized;
}
modelCtrl.$parsers.push(capitalize);
capitalize($parse(attrs.ngModel)(scope)); // capitalize initial value
}
};
});
You can check below for more information on require: 'ngModel' configure setting.
What's the meaning of require: 'ngModel'?

AngularJs: NumberOnly directive

I want to allow numbers only and - sign in textbox.
When i type - sign on IPhone safari it remove value from input like a backspace.
But it is working fine on android and IPad safari.
Here is my directive:
app.directive('numberOnly', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elm, attrs, ngModel) {
var pattern = /[^0-9]/g;
var digitsLength = attrs.digitsLength || 0;
var allowMinus = attrs.allowMinus || false;
if (allowMinus) {
pattern = /(?!^-)[^0-9]/g;
} else {
pattern = /[^0-9]/g;
}
scope.$watch(attrs.ngModel, function (newValue, oldValue) {
if (newValue) {
var result = newValue.toString().replace(pattern, '');
ngModel.$setViewValue(result);
if (digitsLength > 0) {
if (result.charAt(0) === '-') {
if (result.substring(1, result.length).length > digitsLength) {
ngModel.$setViewValue(oldValue);
}
}
else {
if (result.substring(0, result.length).length > digitsLength) {
ngModel.$setViewValue(oldValue);
}
}
}
}
ngModel.$render();
}, true);
}
}
});
app.html
<input type="text" ng-model="number" number-only digits-length="7" >
I think it would be a lot more easier if you use
<input type="number" name="input" ng-model="value">
and check validity of the input. Also you can set digits length by setting min and max values of the input.
$scope.example = {
max: 9999999,
min: 1000000
};
with the following min max settings only 7 digits numbers will be valid.
<input type="number" name="input" ng-model="example.value"
min="{{example.min}}" max="{{example.max}}">
You can try below custom directive which I've used. You can modify the regex here to filter the text.
<input type="text" maxlength="3" replacewith="[^0-9-]" ng-model="number">
app.directive('replacewith',replacewith);
replacewith.$inject = ['$timeout'];
function replacewith($timeout) {
return {
require: 'ngModel',
scope: {
regex: '#replacewith'
},
link: function(scope, element, attrs, model) {
model.$parsers.push(function(val) {
if (!val) {
$timeout(function(){
model.$setValidity('parse', true);
}, 0);
return;
}
var regex = new RegExp(scope.regex);
var replaced = val.replace(regex, '');
if (replaced !== val) {
model.$setViewValue(replaced);
model.$render();
}
return replaced;
});
}
};
}

How do I attach validators on an input field in angular that accesses another model in the form

I have a range input (between [lowerValue] and [upperValue]) on a form and I want to make a reusable directive called 'validateGreaterThan' that can be attached to any form and use the ngModel $validators functionality so I can attach multiple ones onto an input.
You can check a simple demo on jsbin here:
http://jsbin.com/vidaqusaco/1/
I've set up a directive called nonNegativeInteger and that works correctly, however, the validateGreaterThan directive I have isn't working. How can I get it to reference the lowerValue?
I appreciate any help with this.
Here is the basic idea:-
Define 2 directives and let each directive refer to the other field buy passing its name. When the validator runs on the current field you can retrieve the model value of another field and now you have values from both fields and you can ensure the relation between the 2 fields.
As per my code below I have 2 fields minimumAmount and maximumAmount where the minimumAmount cannot be greater than the maximum amount and vice-versa.
<input name="minimumAmount" type="number" class="form-control"
ng-model="entity.minimumAmount"
less-than-other-field="maximumAmount" required/>
<input name="maximumAmount" type="number"
ng-model="entity.maximumAmount"
greater-than-other-field="minimumAmount"
class="form-control"/>
Here we have 2 directives lessThanOtherField and greaterThanOtherField and they both refer to other field as we pass the other field name. greater-than-other-field="minimumAmount" we are passing the other field.
.directive('lessThanOtherField', ['$timeout',function($timeout){
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
var xFieldValidatorName = 'lessThanOtherField';
var form = elm.parent().controller('form');
var otherFieldName = attrs[xFieldValidatorName];
var formFieldWatcher = scope.$watch(function(){
return form[otherFieldName];
}, function(){
formFieldWatcher();//destroy watcher
var otherFormField = form[otherFieldName];
var validatorFn = function (modelValue, viewValue) {
var otherFieldValue = otherFormField.hasOwnProperty('$viewValue') ? otherFormField.$viewValue : undefined;
if (angular.isUndefined(otherFieldValue)||otherFieldValue==="") {
return true;
}
if (+viewValue < +otherFieldValue) {
if (!otherFormField.$valid) {//trigger validity of other field
$timeout(function(){
otherFormField.$validate();
},100);//avoid infinite loop
}
return true;
} else {
// it is invalid, return undefined (no model update)
//ctrl.$setValidity('lessThanOtherField', false);
return false;
}
};
ctrl.$validators[xFieldValidatorName] = validatorFn;
});
}
};
}])
.directive('greaterThanOtherField', ['$timeout',function($timeout){
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
var xFieldValidatorName = 'greaterThanOtherField';
var form = elm.parent().controller('form');
var otherFieldName = attrs[xFieldValidatorName];
var formFieldWatcher = scope.$watch(function(){
return form[otherFieldName];
}, function(){
formFieldWatcher();//destroy watcher
var otherFormField = form[otherFieldName];
var validatorFn = function (modelValue, viewValue) {
var otherFieldValue = otherFormField.hasOwnProperty('$viewValue') ? otherFormField.$viewValue : undefined;
if (angular.isUndefined(otherFieldValue)||otherFieldValue==="") {
return true;
}
if (+viewValue > +otherFieldValue) {
if (!otherFormField.$valid) {//trigger validity of other field
$timeout(function(){
otherFormField.$validate();
},100);//avoid infinite loop
}
return true;
} else {
// it is invalid, return undefined (no model update)
//ctrl.$setValidity('lessThanOtherField', false);
return false;
}
};
ctrl.$validators[xFieldValidatorName] = validatorFn;
});
}
};
}])

In AngularJS, how to write a reusable ng-pattern?

In several places in my application I have to validate that a field is a valid french phone number.
Like this:
<input type="text" ng-pattern="/^0[1-6]{1}((([0-9]{2}){4})|((\s[0-9]{2}){4})|((-[0-9]{2}){4}))$/">
How could I make the regular expression reused by several input fields in my application without copy/pasting the regex?
How could I localize the regex?
Adapt the ngPattern directive :
.directive("customPhonePattern", function () {
return {
restrict: 'A',
require: '?ngModel',
link: function (scope, elm, attr, ctrl) {
if (!ctrl) return;
var patternExp = "/^0[1-6]{1}((([0-9]{2}){4})|((\s[0-9]{2}){4})|((-[0-9]{2}){4}))$/";
attr.$observe('customPhonePattern', function (locale) {
switch (locale) {
case "EN":
patternExp = "";
break;
case "DE":
patternExp = "";
break;
}
var regexp = new RegExp(patternExp);
ctrl.$validate();
});
ctrl.$validators.pattern = function (value) {
return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value);
};
}
};
})
Usage
<input type="text" custom-pattern="FR">
<input type="text" custom-pattern="{{ someValue }}">
You can define the constant values like
var config = {
patternLong: "/^0[1-6]{1}((([0-9]{2}){4})|((\s[0-9]{2}){4})|((-[0-9]{2}){4}))$/",
patternShort: "/^[a-zA-Z0-9_.,-]*$/"
};
angular.module('myApp').value('config', config);
Inject this config in your controllers in which where ever you need, and use like config.patternLong.

min/max validations not working if values are changed later

i have requirement where min value of one field depends on the input given in another field.
<input type="number" name="minval" class="form-control" ng-model="user.minval"
ng-required="true">
this input is used to validate another field
<input type="number" name="inputval" class="form-control" ng-model="user.inputval"
ng-required="true" min="{{user.minval}}">
but this is not working as expected.. if i change the "minval" later the input does not get revalidated..
i have tried setting the initial value for min from JS as was suggested in some solution but thats also not helping...
PLUNKER LINK
use ng-min/ng-max directives
app.directive('ngMin', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attr, ctrl) {
scope.$watch(attr.ngMin, function(){
if (ctrl.$isDirty) ctrl.$setViewValue(ctrl.$viewValue);
});
var isEmpty = function (value) {
return angular.isUndefined(value) || value === "" || value === null;
}
var minValidator = function(value) {
var min = scope.$eval(attr.ngMin) || 0;
if (!isEmpty(value) && value < min) {
ctrl.$setValidity('ngMin', false);
return undefined;
} else {
ctrl.$setValidity('ngMin', true);
return value;
}
};
ctrl.$parsers.push(minValidator);
ctrl.$formatters.push(minValidator);
}
};
});
app.directive('ngMax', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attr, ctrl) {
scope.$watch(attr.ngMax, function(){
if (ctrl.$isDirty) ctrl.$setViewValue(ctrl.$viewValue);
});
var maxValidator = function(value) {
var max = scope.$eval(attr.ngMax) || Infinity;
if (!isEmpty(value) && value > max) {
ctrl.$setValidity('ngMax', false);
return undefined;
} else {
ctrl.$setValidity('ngMax', true);
return value;
}
};
ctrl.$parsers.push(maxValidator);
ctrl.$formatters.push(maxValidator);
}
};
});
I've developed a couple of directives that actually restrict the user from setting an invalid value instead of simply throwing an error when an invalid value is provided.
These directives also do not require ngModel (though I doubt you would use them without) and what's really cool is that it will wrap the value around to the min/max if both settings are provided!
I've tried to simplify the directives as much as possible to make them easier for our readers.
Here is a JSFiddle of the whole thing: JSFiddle
And here are the directives:
app.directive('ngMin', function($parse){
return {
restrict: 'A',
link: function(scope, element, attrs){
function validate(){
if(element
&& element[0]
&& element[0].localName === 'input'
&& isNumber(attrs.ngMin)
&& isNumber(element[0].value)
&& parseFloat(element[0].value) < parseFloat(attrs.ngMin)){
if(isNumber(attrs.ngMax)){
element[0].value = parseFloat(attrs.ngMax);
if(attrs.hasOwnProperty("ngModel"))
$parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMax));
}
else {
element[0].value = parseFloat(attrs.ngMin);
if(attrs.hasOwnProperty("ngModel"))
$parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMin));
}
}
}
scope.$watch(function(){
return attrs.ngMin + "-" + element[0].value;
}, function(newVal, oldVal){
if(newVal != oldVal)
validate();
});
validate();
}
};
});
app.directive('ngMax', function($parse){
return {
restrict: 'A',
link: function(scope, element, attrs){
function validate(){
if(element
&& element[0]
&& element[0].localName === 'input'
&& isNumber(attrs.ngMax)
&& isNumber(element[0].value)
&& parseFloat(element[0].value) > parseFloat(attrs.ngMax)){
if(isNumber(attrs.ngMin)){
element[0].value = parseFloat(attrs.ngMin);
if(attrs.hasOwnProperty("ngModel"))
$parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMin));
}
else {
element[0].value = parseFloat(attrs.ngMax);
if(attrs.hasOwnProperty("ngModel"))
$parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMax));
}
}
}
scope.$watch(function(){
return attrs.ngMax + "-" + element[0].value;
}, function(newVal, oldVal){
if(newVal != oldVal)
validate();
});
validate();
}
};
});
...also, you will need this little helper function as well:
function isNumber(n){
return !isNaN(parseFloat(n)) && isFinite(n);
}
To invoke these directives, just set them on an input box where type="number":
<input ng-model="myModel" ng-min="0" ng-max="1024" />
And that should do it!
When you provide both an ngMin and ngMax, these directive will wrap the value around, so that when your value becomes less than ngMin, it will be set to ngMax, and vice-versa.
If you only provide ngMin or ngMax, the input value will simply be capped at these values.
I prefer this method of preventing bad values rather than alerting the user that they have entered a bad value.

Resources