I have a situation where angular validation sees an email as valid although it's not. The condition that that validation sees valid is example#domain Are there situations where this is an acceptable address?
<div class="form-group" ng-class="{ 'has-error': clientForm.email.$dirty && clientForm.email.$invalid, 'has-success': clientForm.email.$valid }">
<label>Email</label>
<span class="text-danger" ng-show="clientForm.email.$error.required">Email is required.</span>
<span class="text-danger" ng-show="clientForm.email.$error.email">Invalid email address.</span>
<input type="email" name="email" class="form-control input-sm" ng-model="client.email" required />
</div>
You can use a custom directive to validate it however you desire. Here's an example.
angular.module('myApp', [])
.controller('myCtrl', function($scope) {
$scope.client = {};
})
.directive('validEmail', function(emailRegex) {
return {
require: 'ngModel',
link: function($scope, $element, $attrs, ngModel) {
ngModel.$validators.validEmail = function(val) {
if (!val) { return true; }
return emailRegex.test(val);
};
}
};
})
.value('emailRegex', /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
<form ng-app="myApp" ng-controller="myCtrl" name="form">
<label>Email</label>
<span class="text-danger" ng-show="form.email.$error.required">Email is required.</span>
<span class="text-danger" ng-show="form.email.$error.validEmail">Invalid email address.</span>
<input type="text" name="email" ng-model="client.email" required valid-email/>
</form>
However, you should know that validating emails with RegEx is a lot more complicated than you'd ever want to know. Read this.
Related
I follow a solution for checking if a username is already present in the DB: defined in this topic "angularjs: custom directive to check if a username exists"
In my case, I would like to put in practice that when the user wants to update his data; The script has to be launched when the user wants to change his LASTNAME.
At the beginning, the script should not display the error message
Here my controller:
// MY DIRECTIVE FOR CHECKING IF THE USERNAME IS ALREADY USED
app.directive('usernameAvailable', function($timeout, $q, $http, ContactService) {
return {
restrict: 'AE',
require: 'ngModel',
link: function(scope, elm, attr, model) {
model.interation=0;
model.$asyncValidators.usernameExists = function() {
name= elm.val();
return ContactService.searchContactByName(name).success(function(contact){
$timeout(function(){
if(contact.length >0){
model.$setValidity('usernameExists', contact);
//model.$setValidity('unique', false); // For validation criteria in the form
scope.alreadyExist='true';
scope.contacts = contact;
}else{
model.$setValidity('usernameExists', contact);
//model.$setValidity('unique', true); // For validation criteria in the form
scope.alreadyExist='false';
scope.contacts = null;
}
}, 600);
});
};
}
}
});
app.controller('ctrlEditContacts', function ($scope, $routeParams, ContactService){
// LOAD DATA ABOUT THE USER
ContactService.loadPersonById($routeParams.contactId).success(function(contact){
$scope.contact.ID = contact[0].ID;
$scope.contact.LASTNAME = contact[0].LASTNAME;
$scope.contact.FIRSTNAME = contact[0].FIRSTNAME;
});
});
Here my template:
<div class="panel-body">
<form name="ContactForm" class="form-horizontal" role="form" novalidate ng-submit="submitForm(contact)">
<div class="form-group">
<label for="username" class="col-sm-2 control-label">Last Name *</label>
<div class="col-sm-10">
<input type="text" class="form-control"
name="username" maxlength="100" placeholder="Enter Last Name"
required
ng-model="contact.LASTNAME"
username-available
ng-model-options="{ updateOn: 'blur' }">
<div ng-if="ContactForm.$pending.usernameExists">checking....</div>
<div ng-show="alreadyExist=='true'" class="alert alert-info" role="alert" style="margin-top:10px;">
<span class="glyphicon glyphicon-alert" aria-hidden="true"></span>
<span class="sr-only">Error:</span>
Last Name already exists
</div>
</div>
</div>
<div class="form-group">
<label for="txtFirstName" class="col-sm-2 control-label">First Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="txtFirstName" maxlength="100" placeholder="Enter First Name" ng-model="contact.FIRSTNAME">
</div>
</div>
Currently, the script is working.
When the page is loaded data about the user are correctly retrieved and displayed. But the script is equally loaded and the message "Last Name already exists" appears.
So I would like to avoid that and displays this message only when the value of the Last Name is updated (and already used).
Could you tell me how to update the script (of the directive I suppose) for doing that?
Thanks in advance for your help.
The idea is very simple. I have two inputs, and I validate them only if both are touched. At least one has to be different than 0. Where am I going wrong?
The HTML
<div class="form-group" ng-class="{'has-error' : (myForm.$submitted || myForm.for.$touched) && myForm.for.$invalid }">
<label class="col-md-4 control-label" for="for">For</label>
<div class="col-md-8">
<input class="form-control" id="for" name="for" ng-model="item.for" ng-required="(some expression)" type="number" one-not-zero="item.against" one-not-zero-touched="myForm.against.$touched"/>
<div ng-messages="myForm.for.$error" role="alert" ng-show="(myForm.$submitted || myForm.for.$touched) && myForm.for.$invalid">
<div class="help-block" ng-message="required">
REQUIRED
</div>
<div class="help-block" ng-message="oneNotZero">At least one has to be different than 0</div>
</div>
</div>
</div>
<div class="form-group" class="{'has-error' : (myForm.$submitted || myForm.against.$touched) && myForm.against.$invalid }">
<label class="col-md-4 control-label" for="against">Against</label>
<div class="col-md-8">
<input class="form-control" id="against" name="against" ng-model="item.against" ng-required="(some expression) " type="number" one-not-zero="item.for" one-not-zero-touched="myForm.for.$touched"/>
<div ng-messages="myForm.against.$error" role="alert" ng-show="(myForm.$submitted || myForm.against.$touched) && myForm.against.$invalid">
<div class="help-block" ng-message="required">
REQUIRED
</div>
<div class="help-block" ng-message="oneNotZero">At least one has to be different than 0</div>
</div>
</div>
</div>
The Directive
var oneNotZero = function() {
return {
restrict: "A",
require: "ngModel",
scope: {
oneNotZero: "=",
oneNotZeroTouched: "="
},
link: function(scope, element, attrs, ctrl) {
ctrl.$validators.oneNotZero = function (modelValue, viewValue) {
return scope.oneNotZeroTouched ? !((viewValue == 0) && (scope.oneNotZero == 0)) : true;
};
}
};
};
myModule.directive("oneNotZero", oneNotZero);
EDIT: I made some progress, changed the code to my latest version, but it doesn't fully work. If I don't make any changes to the values, and just go trough the inputs until I get to the submit button and hit enter, the validation doesn't fire. SHould I $watch the changes on the inputs?
This will submit the form if at least one field is not 0 else will display an error message.
<form name="myForm" novalidate>
<input name="for" ng-model="item.for" type="number" required>
<input name="against" ng-model="item.against" type="number" required>
<input type="submit" value="Submit">
<div ng-show="myForm.$submitted && (item.for == 0 || item.against == 0)">
At leat one field must be different from 0.
</div>
</form>
I would like to use the AngularJs user registration from http://jasonwatmore.com/post/2015/03/10/AngularJS-User-Registration-and-Login-Example.aspx However, it only prompts for the password once.
I would like to add a "repeat password field and also verify that both passwords are the same.
What am I doing wrong here?
<div class="col-md-6 col-md-offset-3">
<h2>Register</h2>
<div ng-show="vm.error" class="alert alert-danger">{{vm.error}}</div>
<form name="form" ng-submit="vm.register()" role="form">
<div class="form-group" ng-class="{ 'has-error': form.name.$dirty && form.name.$error.required }">
<label for="name">Full name</label>
<input type="text" name="name" id="name" class="form-control" ng-model="vm.user.name" required />
<span ng-show="form.name.$dirty && form.name.$error.required" class="help-block">First name is required</span>
</div>
<div class="form-group" ng-class="{ 'has-error': form.email.$dirty && form.email.$error.required }">
<label for="email">Email address</label>
<input type="text" name="email" id="email" class="form-control" ng-model="vm.user.email" required />
<span ng-show="form.email.$dirty && form.email.$error.required" class="help-block">Last name is required</span>
</div>
<div class="form-group" ng-class="{ 'has-error': form.username.$dirty && form.username.$error.required }">
<label for="username">Requested username</label>
<input type="text" name="username" id="username" class="form-control" ng-model="vm.user.username" required />
<span ng-show="form.username.$dirty && form.username.$error.required" class="help-block">Username is required</span>
</div>
<div class="form-group" ng-class="{ 'has-error': form.password.$dirty && form.password.$error.required }">
<label for="password">Password</label>
<input type="password" name="password" id="password" class="form-control" ng-model="vm.user.password" required />
<span ng-show="form.password.$dirty && form.password.$error.required" class="help-block">Password is required</span>
- I am adding this, but it doesn't work :-(
<div class="form-group" ng-class="{ 'has-error': form.password2.$dirty && form.password2.$error.required }">
<label for="password2">Repeat password</label>
<input type="password" name="password2" id="password2" class="form-control" ng-model="vm.user.password2" required />
<span ng-show="form.password2.$dirty && form.password2.$error.required" class="help-block">Password is required</span>
<span ng-show="form.password2.$dirty && form.password2.$error.required && form.password2 != form.password" class="help-block">Passwords do not match</span>
-
<div class="form-actions">
<button type="submit" ng-disabled="form.$invalid || vm.dataLoading" class="btn btn-primary">Register</button>
<img ng-if="vm.dataLoading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
Cancel
</div>
</form>
</div>
This logic belongs in your controller (or factory, etc), not in the view. You can do something like:
vm.register = function() {
if (vm.user.password !== vm.user.password2) {
vm.alert = 'Passwords must match';
return;
}
...
}
You can also use directive:
.directive('passwordError', function(){
return {
restrict: 'A',
require: 'ngModel',
scope : {
message : "="
},
link : function(scope, element, attrs, ngModel) {
element.on('keydown', function(){
scope.message = '';
return ngModel.$setValidity('passwordError', true);
})
}
}
})
.directive('pwCheck', function(){
return {
require : 'ngModel',
scope : {
newPassword: '=match'
},
link:function(scope, element, attrs, ngModel){
scope.$watch('newPassword', function(){
ngModel.$setValidity('matchError', element.val() === scope.newPassword);
})
element.on('keyup', function(){
scope.$apply(function(){
ngModel.$setValidity('matchError', element.val() === scope.newPassword);
})
})
}
}
})
Here is an example
The check in your ng-show doesn't work because you're trying to compare angular objects not the values of inputs. form.password2 != form.password should be form.password2.$modelValue != form.password.$modelValue.
And second you don't need the form.password2.$error.required check for matching validation. It ruins logic
See plunker. Hope this helps
I have a simple custom directive with a http post call to a url. When the submit button is clicked it supposed to call the url as custom directive attribute is placed inside the tag.
I checked in chrome console that its not getting called. I am not sure where I went wrong.
Code:
<!DOCTYPE html>
<html ng-app="myApp" >
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script>
var app = angular.module('myApp',[]);
app.directive('sendMail', function ($http) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
$http.post('MailSenderServlet.do').success(function (data) {
});
}
};
});
</script>
<title>Registration Form</title>
</head>
<body ng-controller="MainCtrl">
<div class="container">
<h2 class="text-muted">Registration form</h2><br/>
<div>
<form name="myForm" action="RegistrationServlet.do" method="POST" novalidate>
<div class="form-group has-feedback">
<label class="control-label">First name:</label> <input type="text" class="form-control input-sm " name="uname" ng-pattern="/^[a-zA-Z]{3,20}/" ng-model="user.uname" placeholder="First Name" required/>
<span style="color:red" ng-show="myForm.uname.$error.pattern">First name cannot be less than 3 letters with no digits</span>
<span style="color:red" class="error" ng-if="myForm.$submitted && myForm.uname.$error.required">Please fill field above<br></span>
<span style="color:red" class="hide-while-in-focus" ng-show="myForm.uname.$error.unique">Username already exist<br/></span>
<span ng-if="myForm.uname.$valid" class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<button class="form-control btn btn-success" type="submit" name="submit" ng-model="submit" send-mail ">Submit</button>
</form>
</div>
</body>
</html>
it should call right after directive loads, place a alert(); inside the link function and remove current items inside the link function and you will see the alert();
DEMO
but if you want to call a function right after the button click, you need ng-click directive and a controller function to execute after the click in directive controller or link function.
<button ng-click="sendData()" class="form-control btn btn-success" type="submit" name="submit" ng-model="submit" send-mail>Submit</button>
ng-click directive added.
app.directive('sendMail', function($http) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
//alert();
},
controller: function($scope) {
$scope.sendData = function() {
alert('send data here');
}
}
};
});
here is a DEMO
I prefer you shouldn't go for directive if it only contains an ajax call. You can do it just by using ng-click/ng-submit(which is actually meant for forms.) no need of directive here.
You need to correct below certain thing into your code.
We don't need to use ng-model for submit button it doesn't make sense as don't contains any value.
Also you don't need to add action and method attribute on your form, cause anyway you are making from JavaScript code.
While submitting form angular does already provide a directive which is ng-submit.use that would make more sense.
You need to pass data in your post $http.post call.
Markup
<form name="myForm" ng-submit="submit(myForm)" novalidate>
<div class="form-group has-feedback">
<label class="control-label">First name:</label>
<input type="text" class="form-control input-sm " name="uname" ng-pattern="/^[a-zA-Z]{3,20}/" ng-model="user.uname" placeholder="First Name" required/>
<span style="color:red" ng-show="myForm.uname.$error.pattern">First name cannot be less than 3 letters with no digits</span>
<span style="color:red" class="error" ng-if="myForm.$submitted && myForm.uname.$error.required">Please fill field above<br></span>
<span style="color:red" class="hide-while-in-focus" ng-show="myForm.uname.$error.unique">Username already exist<br/></span>
<span ng-if="myForm.uname.$valid" class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<button class="form-control btn btn-success" type="submit" name="submit" send-mail="">Submit</button>
</form>
Controller
$scope.submit = function(form){
if(form.$valid){
$http.post('MailSenderServlet.do', {user: $scope.user})
.success(function (data) {
//
});
}
else
alert("Please validate your form")
}
The issue with your code is simply the controller part you've written
<body ng-controller="MainCtrl">
Either add a controller part, or just remove it, code works fine.
See Demo : http://jsbin.com/hulujarugu/edit?html,console,output
JS:
var app = angular.module('myApp', []);
app.directive('sendMail', function($http) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
alert(1);
$http.post('MailSenderServlet.do').success(function(data) {});
}
};
});
HTML:
<div class="container">
<h2 class="text-muted">Registration form</h2><br/>
<div>
<form name="myForm" action="RegistrationServlet.do" method="POST" novalidate>
<div class="form-group has-feedback">
<label class="control-label">First name:</label> <input type="text" class="form-control input-sm " name="uname" ng-pattern="/^[a-zA-Z]{3,20}/" ng-model="user.uname" placeholder="First Name" required/>
<span style="color:red" ng-show="myForm.uname.$error.pattern">First name cannot be less than 3 letters with no digits</span>
<span style="color:red" class="error" ng-if="myForm.$submitted && myForm.uname.$error.required">Please fill field above<br></span>
<span style="color:red" class="hide-while-in-focus" ng-show="myForm.uname.$error.unique">Username already exist<br/></span>
<span ng-if="myForm.uname.$valid" class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<button class="form-control btn btn-success" type="submit" name="submit" ng-model="submit" send-mail >Submit</button>
</form>
</div>
I have form fields that are validated using required. The problem is, that the error is displayed immediately when the form is rendered. I want it only to be displayed after the user actually typed in the text field, or on submit.
How can I implement this?
Use $dirty flag to show the error only after user interacted with the input:
<div>
<input type="email" name="email" ng-model="user.email" required />
<span ng-show="form.email.$dirty && form.email.$error.required">Email is required</span>
</div>
If you want to trigger the errors only after the user has submitted the form than you may use a separate flag variable as in:
<form ng-submit="submit()" name="form" ng-controller="MyCtrl">
<div>
<input type="email" name="email" ng-model="user.email" required />
<span ng-show="(form.email.$dirty || submitted) && form.email.$error.required">
Email is required
</span>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
function MyCtrl($scope){
$scope.submit = function(){
// Set the 'submitted' flag to true
$scope.submitted = true;
// Send the form to server
// $http.post ...
}
};
Then, if all that JS inside ng-showexpression looks too much for you, you can abstract it into a separate method:
function MyCtrl($scope){
$scope.submit = function(){
// Set the 'submitted' flag to true
$scope.submitted = true;
// Send the form to server
// $http.post ...
}
$scope.hasError = function(field, validation){
if(validation){
return ($scope.form[field].$dirty && $scope.form[field].$error[validation]) || ($scope.submitted && $scope.form[field].$error[validation]);
}
return ($scope.form[field].$dirty && $scope.form[field].$invalid) || ($scope.submitted && $scope.form[field].$invalid);
};
};
<form ng-submit="submit()" name="form">
<div>
<input type="email" name="email" ng-model="user.email" required />
<span ng-show="hasError('email', 'required')">required</span>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
If you want to show error messages on form submission, you can use condition form.$submitted to check if an attempt was made to submit the form. Check following example.
<form name="myForm" novalidate ng-submit="myForm.$valid && createUser()">
<input type="text" name="name" ng-model="user.name" placeholder="Enter name of user" required>
<div ng-messages="myForm.name.$error" ng-if="myForm.$submitted">
<div ng-message="required">Please enter user name.</div>
</div>
<input type="text" name="address" ng-model="user.address" placeholder="Enter Address" required ng-maxlength="30">
<div ng-messages="myForm.name.$error" ng-if="myForm.$submitted">
<div ng-message="required">Please enter user address.</div>
<div ng-message="maxlength">Should be less than 30 chars</div>
</div>
<button type="submit">
Create user
</button>
</form>
You can use angularjs form state form.$submitted.
Initially form.$submitted value will be false and will became true after successful form submit.
Erik Aigner,
Please use $dirty(The field has been modified) and $invalid (The field content is not valid).
Please check below examples for angular form validation
1)
Validation example HTML for user enter inputs:
<form ng-app="myApp" ng-controller="validateCtrl" name="myForm" novalidate>
<p>Email:<br>
<input type="email" name="email" ng-model="email" required>
<span ng-show="myForm.email.$dirty && myForm.email.$invalid">
<span ng-show="myForm.email.$error.required">Email is required.</span>
<span ng-show="myForm.email.$error.email">Invalid email address.</span>
</span>
</p>
</form>
2)
Validation example HTML/Js for user submits :
<form ng-app="myApp" ng-controller="validateCtrl" name="myForm" novalidate form-submit-validation="">
<p>Email:<br>
<input type="email" name="email" ng-model="email" required>
<span ng-show="submitted || myForm.email.$dirty && myForm.email.$invalid">
<span ng-show="myForm.email.$error.required">Email is required.</span>
<span ng-show="myForm.email.$error.email">Invalid email address.</span>
</span>
</p>
<p>
<input type="submit">
</p>
</form>
Custom Directive :
app.directive('formSubmitValidation', function () {
return {
require: 'form',
compile: function (tElem, tAttr) {
tElem.data('augmented', true);
return function (scope, elem, attr, form) {
elem.on('submit', function ($event) {
scope.$broadcast('form:submit', form);
if (!form.$valid) {
$event.preventDefault();
}
scope.$apply(function () {
scope.submitted = true;
});
});
}
}
};
})
3)
you don't want use directive use ng-change function like below
<form ng-app="myApp" ng-controller="validateCtrl" name="myForm" novalidate ng-change="submitFun()">
<p>Email:<br>
<input type="email" name="email" ng-model="email" required>
<span ng-show="submitted || myForm.email.$dirty && myForm.email.$invalid">
<span ng-show="myForm.email.$error.required">Email is required.</span>
<span ng-show="myForm.email.$error.email">Invalid email address.</span>
</span>
</p>
<p>
<input type="submit">
</p>
</form>
Controller SubmitFun() JS:
var app = angular.module('example', []);
app.controller('exampleCntl', function($scope) {
$scope.submitFun = function($event) {
$scope.submitted = true;
if (!$scope.myForm.$valid)
{
$event.preventDefault();
}
}
});
Invoking of validation on form element could be handled by triggering change event on this element:
a) exemple: trigger change on separated element in form
$scope.formName.elementName.$$element.change();
b) exemple: trigger change event for each of form elements for example on ng-submit, ng-click, ng-blur ...
vm.triggerChangeForFormElements = function() {
// trigger change event for each of form elements
angular.forEach($scope.formName, function (element, name) {
if (!name.startsWith('$')) {
element.$$element.change();
}
});
};
c) and one more way for that
var handdleChange = function(form){
var formFields = angular.element(form)[0].$$controls;
angular.forEach(formFields, function(field){
field.$$element.change();
});
};