issue with ngPattern - angularjs

I am trying to design a nifty expiration date input on a credit card checkout form that will automatically insert a " / " between expiration month and year while the user is typing. The model no longer picks up the input value since I have introduced ngPattern validation to the input. Angular only allows a model to pick up the input value once the validation has succeeded. This basically makes my nifty feature not work due to my code. Can someone find a way around this. below is my code.
html
<input ng-keyup="checkout.updateExp()" class="form-control" type="text" maxlength="7" placeholder="mm / yy" required autocomplete="off" name="exp" ng-pattern="/\d{2}\s\/\s\d{2}/" ng-model="checkout.cf.exp">
controller function
vm.updateExp = function(){
var separator=" / ";
//add separator
if(vm.cf.exp.length==2){//-----> cannot process since ngPattern makes exp undefined till pattern is met
vm.cf.exp = vm.cf.exp.substring(0,2) + separator;
}
//remove separator
if(vm.cf.exp.length==4){
vm.cf.exp = vm.cf.exp.substring(0,1);;
}
};

Why not validate it manually using a regular expression instead of having it done using ng-pattern? You can set the $validity of the field manually just like angular would do it using ng-pattern.
In the html add
ng-keyup="checkout.updateExp(form.exp)" name="exp"
form.exp is the form and then the name of the input field. I do not know what the form name is so you will have to replace it accordingly.
vm.updateExp = function(formModel){
/* existing code omitted */
var expression = /\d{2}\s\/\s\d{2}/; // create RegEx
formModel.$setValidity("pattern", expression.test(vm.cf.exp)); // set validity to whatever name you want, I used the name pattern
};

Related

Angular can I have 2 ng-pattern to validate the same filed

My current input looks like this
<input type="email" name="email"
ng-pattern="emailRegex"
ng-change="emailChanged()"
required />
My ng-pattern="ctrl.emailRegex" validates if an email is valid or not
/^[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{1,63}$/;
But I would like to block info#, admin#, help#, sales# emails, so I changed the regex to
/^(?!(?:info|admin|help|sales)#)[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{1,63}$/
So far so good, but I would like to show
Invalid email
to "invalid#!!!!!.com!"
and
info#, admin#, help#, sales# emails are not allowed
to info#test.com
How can I have 2 ng-pattern in the same input?
Thanks
You can validate only one pattern for an input. And, even if you can sort of do it somehow by using a directive, it would be too dirty a solution. Instead, I would recommend validating the input against regex(es) inside the function of ng-change and use formName.inputName.$setValidity to set custom validity of the input. This lets you have a fallback if one pattern is passed.
So, for example, ctrl.emailChanged could probably have something like this,
ctrl.emailChanged = function() {
var emailPattern = /^[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{1,63}$/;
var customValidateEmail = /^(?!(?:info|admin|help|sales)#)[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{1,63}$/;
if(!emailPattern.test(ctrl.registrationForm.email)) {
// Invalid email
} else if (customValidateEmail.test(ctrl.registrationForm.email)) {
// handle accordingly
}
// rest of the things
...
}
Alternatively, you can move the validation logic to another function and just call it from emailChanged.

AngularJS - regular expression which should not start & end with space and should not consist double quotation (")

I have written ng-pattern for not to start and end with space.
And trying to match double quotation in $watch.
But it is not working. ng-pattern is also not working
my ng-pattern is:
<input type="text" class="form-control" ng-model="wifiResult.ssid"
name="ssid"
ng-class="{'inputError' : errorMsg}"
ng-minlength="1"
ng-maxlength="32"
ng-pattern="/^[^\s]+(\s+[^\s]+)*$/"
required >
$watch in JS is:
$scope.$watch('wifiResult.ssid', function(scope){
var regexToRestrict = /^["]+$/;
if(scope){
var pressChar = scope.slice(-1);
if(pressChar.match(regexToRestrict)){
scope = scope.slice(0,-1); // try to replace " to blank
}
else{
console.log('not matched');
}
}
else{
console.log('no scope');
}
});
Is there any other way to do this?
Thanks in advance !
You can change your regex to like this ng-pattern='/^[^\\\\./:*?\"<>|][^\\\\/:*?\"<>|]{0,254}$/' in your html to prevent user from entering (") in input and form can throw an error saying it's an invalid input.
In angular ng-trim is by default set to true so any white spaces surrounding user input are removed before assigning to ng-model.
You don't need a watcher unless and until you want the input value to be (") free every time user tries to enter some value in input field.It's an unnecessary operation to validate every time user changes something.

Input is invalid even when it's error is empty

I'm trying to create my own validation for password confirm, and putting my error on $error. this is my code:
html:
<input ng-model="user.password2" type="password" name="password2" required
ng-keyup="confirmPassword(user.password, user.password2)">
<div ng-messages="register.password2.$error" ng-if="register.password2.$dirty">
<div ng-message="required">Password is required</div>
<div ng-message="passwordsDontMatch">Passwords don't match</div>
</div>
JS:
$scope.confirmPassword = function (pass1, pass2) {
if (angular.isUndefined(pass1) || angular.isUndefined(pass2) || pass1.trim() != pass2.trim()) {
$scope.register.password2.$error["passwordsDontMatch"] = true;
} else {
delete $scope.register.password2.$error["passwordsDontMatch"];
}
console.log($scope.register.password2.$error);
};
it looks like it's working. when the passwords are the same, the message is not displayed and indeed the $error object is empty. But the input is still invalid: ($scope.register.password2.$invalid == true)
you can see what I'm talking about in this plunkr: http://plnkr.co/edit/ETuVqsdSaEBWARvlt4RR?p=preview
try 2 identical passwords. the message will disappear but when you blur from the input, it's still red because internally it's $invalid
The problem probably comes from the fact that you're not typing a password in the first field that matches your regex pattern. The first password is thus undefined, since it doesn't respect the ng-pattern validation rule.
That said, you shouldn't modify the $error array directly. Instead, you should set the validity of the field using $setValidity(). That will not only set and remove the error automatically, but also deal with the $invalid/$valid properties, add and remove the CSS classes, etc.
var valid = !((angular.isUndefined(pass1) || angular.isUndefined(pass2) || pass1.trim() != pass2.trim()));
$scope.register.password2.$setValidity("passwordsDontMatch", valid);
Here's a working example. But remember to enter a valid password in the first place.
Also, instead of implementing this check with ng-keyup, you should make it a directive, which would add a validator to the validators of the form input. This would make sure the check is made whatever the way the second password is entered (i.e. via copy/paste using the mouse only, or simply by prepopulating the form programmatically.

Warnings in AngularJs

Angularjs has great infrastructure for form validation and showing error messages. But, I am in a situation that I have to show a warning message to a user in a specific scenario. Here is the diagram of my simple form
The form has required and pattern validation applied on both fields. In addition to this validation I want a warning message to be displayed to the user if VatAmount is not 20 percent of the InvoiceAmount. The warning will differ from validation in following aspects
It will not prevent the form submission
It will only appear if both fields (InvoiceAmount and VATAmount) are
valid
The warning should have a button or link that would read "Change and
proceed". When user presses that button the warning message will
hide and focus will be set to VATAmount field.
I believe this is a prefect use case for creating a directive. Actually, I have given it a try and put my effort in the form of a plunker. But my directive does not handle following cases
It appears even if the fields involved in warning are invalid
The show and hide functionality is not implemented (have no idea how
to target it)
Here is the link to the plunker
Your plunkr demo was on the right track; really you just needed to check for the special cases of when one of the values was empty.
I'd suggest calculating the fraction and storing it in the scope, and then watching that to see whether you should display your tax rate warning. Here's how to calculate the fraction. If either invoice.Amount or invoice.VAT is empty, the fraction will be set to null.
if (amt == null || vat == null) {
$scope.warning.fraction = null;
return;
}
$scope.warning.fraction = vat / amt;
This works because those properties will be set to undefined if the user doesn't enter a valid number due to your use of ng-pattern.
However, while it's nice to encapsulate this in a directive, you don't need to compile the template yourself. Just use the built-in ng-transclude directive. Then you can include a button that references the current scope like this:
<vat-warning>
Vat Amount is not 20%.
<button ng-click="invoice.VAT = invoice.Amount / 5">change</button>
</vat-warning>
Your directive would contain this declaration:
transclude: true,
template: '<span class="alert-warning" ng-show="warning.show" ng-transclude></span>'
Plus a controller to update the directive's local scope to manipulate the warning object. Here's an updated demo.
You need to calculate visibility of vat-warning tag in controller on basis of $error.required and $error.pattern of invoiceAmount and vatAmount and then use it as below:
$scope.isInvoiceAmountInvalid = function () {
var error = $scope.invoiceForm.invoiceAmount.$error;
var required = error.hasOwnProperty("required") && error.required;
var pattern = error.hasOwnProperty("pattern") && error.pattern;
console.log("Inside isInvoiceAmountInvalid", error, required, pattern);
return (required || pattern);
};
$scope.isVatAmountInvalid = function () {
var error = $scope.invoiceForm.vatAmount.$error;
var required = error.hasOwnProperty("required") && error.required;
var pattern = error.hasOwnProperty("pattern") && error.pattern;
console.log("Inside isVatAmountInvalid", error, required, pattern);
return (required || pattern);
};
Here is an updated plunker for the same

input type="date" not show value in chrome > 30

from my SQL Server i become a value of "03.11.2014". This value i want show in a input type of date like:
<input type="date" value={{myDate}}>
In the Internet Explorer this will show right, but without a date picker. Show like a textbox.
In Google Chrome i don´t became any value.
I have googled, but it looks like that Chrome expected the date in "2014-11-03".
What´s the right workarround to show a datetime picker with the right value in BOTH browsers?
You'll want to put quotes around "{{myDate}}" so {{myDate}} can be passed appropriately to the value attribute.
You'll want to create your own filter that will parse that string from being mm.dd.yyyy to yyyy-dd-mm. Depending on your datepicker, you then might need to then re-convert the string you just created to become a date again. If so, just add a line in the filter that does so.
Here's an example to start from for the filter:
angular.module('myApp', [])
.filter('reformatDate', function() {
return function(input) {
input = input.splice('.');
return input[2] + "-" + input[1] + "-" + input[0];
};
})
which you then call (after injecting the 'myApp' dependency in the controller):
value="{{myDate | reformatDate}}"

Resources