AngularJS - Dynamic pattern to validate input field - javascript

Basically what I need to be able to register two types of code. The code type A has only numbers and the code Type B has numbers, one hyphen, one alphabetic value and one numeric value.
Hypothetical situation:
I register the code type A, the custom directive validate all values.
I need to register the code type B, I check the option 'Validate code
Type B', the pattern is changed in order to make the validation, then all values entered are validated.
Code - Type A
12345678
32445678
56535678
Code with complement number - Type B
32445678-a1
32445678-a2
65434567-b1
The form
<form>
<span>Insert code:</span><br/>
<input type="text" data-ng-model="code" code-type> <br/>
<input type="checkbox" data-ng-model="validateCodeTypeB" /> Validate code Type B
</form>
Note: When the 'validateCodeTypeB' option is checked the regex will be changed too. But I don't know how to implement the second regex in order to validate the code Type B.
See the example
And the directive
app.directive('codeType', function () {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModelCtrl) {
function codeTypeA(text) {
if (text) {
var transformedInput = text.replace(/[^0-9]/g, '');
if (transformedInput !== text) {
ngModelCtrl.$setViewValue(transformedInput);
ngModelCtrl.$render();
}
return transformedInput;
}
return undefined;
}
ngModelCtrl.$parsers.push(codeTypeA);
}
}
});

Here I have made you plnkr for your solution:
if(!scope.codeType){
transformedInput = text.replace(/[^0-9]/g, ''); // For CodeTypeA
} else {
transformedInput = text.replace(/[^a-z]/g,''); // For CodeTypeB, change it to your own regex
}
https://plnkr.co/edit/IfIeXhy7vZacLi2jKsMs?p=preview
but regex is different for CodetypeB , change it to your regex for codetypeB and its good to go.

Related

Force pattern on input Angular

So I am new to Angular.
What I want to do is to force an input field (text) to be as the following:
*Uppercase only, or change the letters to uppercase automatically
*Max 30 characters
*No special characters
If someone tries to insert a special character it won't be displayed at all.
So it's not only validation.
It's accepting those rules on the input.
And I want all of this to be done on that field on a specific condition: let's say when the placeholder is equal to "Nickname" which is in my model formField.CustomFieldName
Thank you in advance
There are at least two ways you can do. Use ng-keypress to either check each character you enter or check regular expression on the input.
I am not going to give the entire solution but you can go from here.
<div ng-app="myApp">
<div ng-controller="myController">
<input type="text" ng-model="yourInput" ng-keypress="yourKeypressFunction($event)">
</div>
</div>
In your js:
var myApp = angular.module('myApp',[]);
myApp.controller('myController', ['$scope', function($scope) {
$scope.yourInput = "";
$scope.yourKeypressFunction = function(event) {
console.log(event); // check for event.which, if it is not the char you want, return;
console.log($scope.yourInput); // check for regular expression
}
}]);
https://docs.angularjs.org/api/ng/directive/ngKeypress
Try onchange event and write a method in the component that you are looking to do, or if you are using observables then try to use the observable methods to transform your input to your requirement.
Check this link http://blog.angular-university.io/introduction-to-angular-2-forms-template-driven-vs-model-driven/
This has good explanation how to deal with forms and input fields
you can do it like this using jQuery for restriction of characters
$("#youTextFieldId").keypress(function(e)
{
var code = e.which || e.keyCode;
// 65 - 90 for A-Z and 97 - 122 for a-z 95
if (!((code >= 65 && code <= 90) || !(code >= 97 && code <= 122) )
{
e.preventDefault();
}
});
and for your text limit
<input id="youTextFieldId" type="text" maxlength="30" style="text-transform:uppercase">
try to use ng-pattern=you pattern with maxlength in your text field. for eg:
<input type="text" ng-pattern="/^[a-zA-Z0-9]*$/" maxlength="30">
The /^[a-zA-Z0-9]*$/ will allow you to enter only character and numbers only. not any special characters.
Use https://github.com/candreoliveira/ngMask with a little study of documentation your pattern is very easy to create and it will also force that the user inputs the desired pattern only and on top of that you can just write maxlength="30" ,input type="text"
Look out at this example for better understanding in the demo of the ngMask ngMask String Example Demo
So this is the solution to this problem.
I hope it helps someone.
I made a fiddle for this: http://jsfiddle.net/m152d0t9/
var app = angular.module("myApp", []);
function Fiddle($scope) {}
app.directive('customInputFormat', function() {
return {
restrict: 'A',
require: '?ngModel',
scope: {
customInputFormat: '='
},
link: function(scope, elm, attr, ctrl) {
if (!ctrl) {
return;
}
scope.$watch(attr.ngModel, function(newVal, oldVal) {
if (!scope.customInputFormat) {
return;
}
if (newVal && newVal.length) {
var newStr = newVal.replace(/[^a-zA-Z0-9\s]*/g, '').toUpperCase();
if (newStr.length > 20) {
newStr = newStr.substring(0, 20);
}
ctrl.$setViewValue(newStr);
ctrl.$render();
}
})
}
};
});
And for the HTML:
<ul ng-controller="Fiddle">
<li>
<label data-ng-init="condition = true;" for="foobar"> Input text</label>
<input custom-input-format="condition" id="foobar" name="foobar" type="text" ng-model="foo" required />
</li>
</ul>

Alphanumeric value in ngModel outputs to uppercase in AngularJS

I have a form with input fields. One input field allows alphanumeric values. But if the value contains letters, then the letters have to be uppercase. How can I implement this approach? Is it possible to define this in the input field, when the user does an input then the letters are automatically shown in uppercase?
The View:
<div class="form-group-sm has-feedback">
<label class="control-label" for="article-id">Article Nr.</label>
<input type="text"
class="form-control"
name="Article"
id="article-id"
ng-model="selected.article"
ng-pattern="/^[a-zA-Z]{2}[a-zA-Z\d]{9}[0-9]$/"
ng-required="true"
/>
</div>
...
//the other inputs are the same definition
It is important for me to save the value in the DB with uppercase letters.
Just create a simple directive ,this answer is based on the answer here: Angular.js: How to autocapitalize an input field?.
myApp.directive('capitalize', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
var capitalize = function(inputValue) {
if(inputValue == undefined) inputValue = '';
var capitalized = inputValue.toUpperCase();
if(capitalized !== inputValue) {
modelCtrl.$setViewValue(capitalized);
modelCtrl.$render();
}
return capitalized;
}
modelCtrl.$parsers.push(capitalize);
capitalize(scope[attrs.ngModel]); // capitalize initial value
}
};
});
HTML like -
<input type="text" ng-model="name" capitalize>
The first Answer works fine. But I've solved this with this CSS code:
CSS:
#article-id {
text-transform: uppercase;
}

Apply number filter on input field in AngularJS

How do we apply number filter on input field? I works fine on displaying on non-input field. However when I set the filter on input field I get an error.
<input type="number" name="input" ng-model="value2 | number:2"
min="0" max="99" size="20">
Error: [ngModel:numfmt] http://errors.angularjs.org/1.3.8/ngModel/numfmt?p0=98.77
at Error (native)
at http://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js:6:416
Here is a plunk for testing.
number format
You can't apply a filter to ng-model.
See specifically this answer (not marked as the answer) for more information:
https://stackoverflow.com/a/14425022/1452497
Short and sweet:
...the intention of AngularJS inputs and the ngModel
directive is that invalid input should never end up in the model. The
model should be always valid.
Consider also that the expression inside of ng-model needs to be assignable from the parser.
ng-model="testA" eventually breaks down to: testA = some-input-value
This wouldn't work as: testA | number:2 = some-input-value
You should use a formatter or parser for this (outside of the view).
This error:
Error: [ngModel:numfmt] http://errors.angularjs.org/1.3.5/ngModel/numfmt?p0=1
check your model: don't using $scope.mymodel = '1';
to use $scope.mymodel = 1;
This directive validate only numbers on input.
angularMainModule.directive('onlyNumbers', 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) {
if($.inArray(event.which,keyCode) == -1) {
scope.$apply(function(){
scope.$eval(attrs.onlyNumbers);
event.preventDefault();`enter code here`
});
event.preventDefault();
}
});
};
});

Angularjs form validation order

I have a simple html form containing regular text input. ng-minlength, ng-maxlength and ng-pattern angular built-in form input directives are set on the input.
Problem: ng-pattern check is applied before the length check by ng-minlength and ng-maxlength.
Question: how can I change the default check order: i.e. first check for the length, then apply pattern check?
Example:
<body ng-app>
<div>
<form name="myForm">
Name: <input name="name" type="text" ng-model="name" ng-minlength="3" ng-maxlength="16" ng-pattern="/^\w+$/"/>
<div ng-show="myForm.name.$dirty && myForm.name.$invalid">
<span ng-show="myForm.name.$error.pattern">Pattern error</span>
<span ng-show="myForm.name.$error.minlength || myForm.name.$error.maxlength">Length error</span>
</div>
<br/>
<input type="submit" value="Submit">
</form>
</div>
</body>
Current behavior:
enter "#" - see "Pattern error"
enter "###" - see "Pattern error"
Desired behavior:
enter "#" - see "Length error"
enter "###" - see "Pattern error"
FYI, related jsfiddle.
Thanks in advance.
Write your own directive:
var mod = angular.module("myApp", []);
mod.directive("nameValidation", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attrs, ngModelCtrl) {
var validate = function (value) {
var minLen = parseInt(attrs.myMinlength, 10),
maxLen = parseInt(attrs.myMaxlength, 10),
pattern = attrs.myPattern,
match = pattern.match(/^\/(.*)\/([gim]*)$/),
lenErr = false;
if (match) {
pattern = new RegExp(match[1], match[2]);
}
if (!ngModelCtrl.$isEmpty(value)) {
ngModelCtrl.$setValidity("pattern", true);
if ((minLen && value.length < minLen) || (maxLen && value.length > maxLen)) {
ngModelCtrl.$setValidity("length", false);
lenErr = true;
}
else {
ngModelCtrl.$setValidity("length", true);
lenErr = false;
}
if (!lenErr) {
if (match && !pattern.test(value)) {
ngModelCtrl.$setValidity("pattern", false);
}
else {
ngModelCtrl.$setValidity("pattern", true);
}
}
}
else {
ngModelCtrl.$setValidity("length", true);
ngModelCtrl.$setValidity("pattern", true);
}
}
ngModelCtrl.$parsers.push(validate);
ngModelCtrl.$formatters.push(validate);
}
}
});
Then in your HTML, include the app and use the directive:
<body ng-app="myApp">
<div>
<form name="myForm">
Name: <input name="name" type="text" ng-model="name" name-validation="" my-minlength="3" my-maxlength="16" my-pattern="/^\w+$/"/>
<div ng-show="myForm.name.$dirty && myForm.name.$invalid">
<span ng-show="myForm.name.$error.pattern">Pattern error</span>
<span ng-show="myForm.name.$error.length">Length error</span>
</div>
<br/>
<input type="submit" value="Submit">
</form>
</div>
</body>
The directive uses my-minlength, my-maxlength, and my-pattern for the three values. If length fails, that will trip first. If not, then pattern will show as error if it doesn't match. Consider renaming this directive if you want to use it other places besides name as minlength, maxlength, and pattern can be passed to it via attributes. If they are left off, they will be ignored.
See jsfiddle: http://jsfiddle.net/4zpxk/6/
I searched in angular code why this behavior. Then in the function 'textInputType' that it's the specific function that handles text inputs for the angular 'input' directive I found this at the end of this function, where we can see three blocks of code.
// pattern validator
if (pattern){
//validator logic
}
// min length validator
if (attr.ngMinlength) {
//validator logic
}
// max length validator
if (attr.ngMaxlength) {
//validator logic
}
So, no matter if you change the declaration order of your ng-* attributes in the html input element you will always get same result but if you change the order of the blocks, I mean, put the min length validator block before pattern validator block you will have the result that you expect.
This is a solution for your problem but you have to make a litte change in angular code and I don't know if you really like this. But you got a very common situation where order of the declaration of validation concepts matters, so, something more must be done to handle this. Thanks
You cannot change the default check order unfortunately.
One solution is to write a custom validator, not that difficult. Based on this answer, I came up with this code (fiddle)
Usage: There is an array of validation functions in the scope, they get passed to our custom directive "validators" as:
<input name="name" type="text" ng-model="name" validators="nameValidators"/>
A validator function would look like (e.g. for the minlength constraint):
function minlength(value, ngModel) {
if( value == null || value == "" || value.length >= 3 ) {
ngModel.$setValidity('minlength', true);
return value;
}
else {
ngModel.$setValidity('minlength', false);
return;
}
}
Important points are: it takes the value and the ngModel as arguments, performs the test (here value.length >= 3) and calls ngModel.$setValidity() as appropriate.
The directive registers the given functions with ngModel.$parsers:
app.directive("validators", function($parse) {
return {
restrict: "A",
require: "ngModel",
link: function(scope, el, attrs, ngModel) {
var getter = $parse(attrs.validators),
validators = getter(scope),
i;
for( i=0; i < validators.length; i++ ) {
ngModel.$parsers.push((function(index) {
return function(value) {
return validators[index](value, ngModel);
};
})(i));
}
}
};
});
Many details can be tweaked and improved, but the outline works (again link to fiddle). Now the order of validation is explicitly set by the order of the validator functions in the nameValidators array.
If you use ng-messages you should be able to set the order via the order of ng-message elements, e.g:
<div ng-messages="field.$error">
<ul class="validation-errors">
<li ng-message="required">This has the highest prio</li>
<li ng-message="min">Second in command</li>
<li ng-message="max">I'm last</li>
</ul>
</div>
Also the docs on this: https://docs.angularjs.org/api/ngMessages/directive/ngMessages
i just changed the order of your directives, pattern first
<input name="name" type="text" ng-model="name" ng-pattern="/^\w+$/" ng-minlength="3" ng-maxlength="16"/>
EDIT: uuum, tested your fiddel without changes and it shows your desired behavior ...
directives are compiled by priority, bbut i don't know how to set angulars directives priority ... sorry, should have tested this first

Angular JS Email Validation with unicode characters

I have a sign up form for an application, and angular js is responsible for its validation.
I ran into an issue when Angular js wasn't accepting an email address which has apostrophe in it. "Pear'lpeerh.shin#xyz.com" .
I found out that angularJs doesnt like unicode characters in email address.
Has anyone else came across an issue like this, I am interested in knowing my options to get away with this bug in angularJs.
Any inputs are appreciated. Thanks !
If having html5 <input type=email /> is not critical, you can use <input type=text /> and pattern validation
<input type="text" ng-model="field" ng-pattern="EMAIL_REGEXP" />
and you can use regex that #Andy Joslin posted in his answer
$scope.EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+#[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
AngularJS uses this regular expression to test email: https://github.com/angular/angular.js/blob/master/src/ng/directive/input.js#L4
What you could do is write a directive that checks it yourself. Just copy the one from AngularJS and use your own regexp: https://github.com/angular/angular.js/blob/master/src/ng/directive/input.js#L606-L614
myApp.directive('nanuEmail', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elm, attrs, model) {
//change this:
var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/;
var emailValidator = function(value) {
if (!value || EMAIL_REGEXP.test(value)) {
model.$setValidity('email', true);
return value;
} else {
model.$setValidity('email', false);
return undefined;
}
model.$parsers.push(emailValidator);
model.$formatters.push(emailValidator);
}
};
});
Then you can just do:
<input nanu-email ng-model="userEmail">
I just updated the regex in the angular.js file (added " ' " in the expression) and it worked, without making any other changes.
EMAIL_REGEXP = /^[A-Za-z0-9._%+-']+#[A-Za-z0-9.-]+.[A-Za-z]{2,4}$/ . Thanks Vittore, for giving me the idea to update REGEX. :)
why do you return undefined?
Refactoring of the function:
var verificationEmail = function (viewValue) {
if ((typeof viewValue != "undefined") && viewValue != "") {
return regex.test(viewValue);
}
};
Angular do not support the apostrophe(') in email Id. If you need to validate the apostrophe in Angular, you need to change the regular expression from:
(/^[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/)
To:
/^[A-Za-z0-9._%+'-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/.
It will work perfectly.

Categories