I'm using a small script to validate a postcode, which works and stops the user entering an invalid password, but when an invalid post code is entered you then can't submit a correct entry. For example, if I enter 'ST' I get the message telling me the postcode is invalid, so without refreshing the page manually I enter 'ST6 1SA' (which is a valid Stoke postcode) and I can't submit the form, I just keep getting the invalid tool tip advising me the post code is not in the correct format.
JS:
<script>
// Validate the postcode before it's sent
(function () {
var postcode = document.getElementById('postcode-entry');
var wrapper = document.getElementById('validation');
var notify = document.createElement('div');
var mnisLookup = document.getElementById('mnis-results');
var matchingClients = document.getElementById('matching-clients');
var postcodeWrapper = document.getElementById('postcode-wrapper');
notify.id = 'notify';
notify.style.display = 'none';
wrapper.appendChild(notify);
postcode.addEventListener('invalid', function (event) {
if (!event.target.validity.valid) {
notify.textContent = 'Please enter a valid postcode e.g. ST1, ST1 4BJ';
notify.className = 'error';
notify.style.display = 'block';
postcode.className = 'form-control invalid';
}
});
})();
</script>
HTML:
<form id="postcode-wrapper" class="form-horizontal">
<div id="postcode-lookup" class="form-group">
<label for="postcode-entry" class="col-sm-1">Postcode:</label>
<div id="postcode-entry-wrapper" class="col-sm-3">
<input type="text" pattern="^(([gG][iI][rR] {0,}0[aA]{2})|((([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y]?[0-9][0-9]?)|(([a-pr-uwyzA-PR-UWYZ][0-9][a-hjkstuwA-HJKSTUW])|([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y][0-9][abehmnprv-yABEHMNPRV-Y])))( {0,}[0-9][abd-hjlnp-uw-zABD-HJLNP-UW-Z]{2})?))$" oninvalid="setCustomValidity('Invalid Post Code Format ')" class="form-control" id="postcode-entry" placeholder="Enter your postcode" name="Postcode" />
</div>
<div class="col-sm-1">
<input id="search" type="submit" value="Search" class="btn btn-default" />
</div>
<div id="validation" class="col-sm-7"></div>
</div>
</form>
Just a quick note that may affect how the page is refreshing, this is inside an MVC Razor page and wrapped with Html.BeginForm - not sure if that makes a difference?
While debugging your code, i found that the event.target.validity.valid was returning false even if the input was valid e.g. 'ST6 1SA'. This was occuring because it does not update the custom validation for the new input and the previous state persists even after entering the valid input.
So to update and reset the previous validation, you have to reset setCustomValidity('') on input change, i.e. oninput="setCustomValidity('')"
Please replace this code:
<input type="text" pattern="^(([gG][iI][rR] {0,}0[aA]{2})|((([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y]?[0-9][0-9]?)|(([a-pr-uwyzA-PR-UWYZ][0-9][a-hjkstuwA-HJKSTUW])|([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y][0-9][abehmnprv-yABEHMNPRV-Y])))( {0,}[0-9][abd-hjlnp-uw-zABD-HJLNP-UW-Z]{2})?))$" oninvalid="setCustomValidity('Invalid Post Code Format ')" class="form-control" id="postcode-entry" placeholder="Enter your postcode" name="Postcode" oninput="setCustomValidity('')"/>
Related
I'm using a pretty simple form to submit something to our API. I added some form validation using a directive called Angular UI Form Validation. I'm just submitting an object with 2 properties; 'id', and 'points'. I'm running into a strange issue that I've been having a lot of trouble solving and hope I can get some help here.
The form validation works fine. If I enter a value into the input field that doesn't pass, you can't submit the form and a message beneath the input saying why appears. However, if I then remove the incorrect input and put in a correct input, the message is still there. If I click on the submit button, the message disappears. If I click the submit button again, it submits. I've noticed, however, that if I just press the enter key it submits right away.
I threw some console.log's in there, and it looks like the problem is that a formData object isn't created on the first click; only on the second. Here is the html:
<form name="pointsField">
<p><input type="number" ng-model="formData.points"
validation-only-numbers="true"
validation-field-required="{message:'Points value is required.',value:true}"
min="0"/></p>
<p><button class="btn btn-success" type="button" ng-click="updatePoints(pointsField)" ng-disabled="loading">
<span ng-if="loading"><i class="fa fa-circle-o-notch fa-la fa-spin"></i></span>Update Points
</button></p>
</form>
And here is the Javascript (keep in mind that the formData object is created when the controller is initialized, and it is just an empty object):
$scope.updatePoints = function(formData) {
console.log('formData ', formData);
$scope.$broadcast('runCustomValidations');
if(formData.$invalid){
return;
}
var pointsObject = {
"id": $scope.userId,
"points": $scope.formData.points
};
$scope.loading = true;
User.updateUserPoints(pointsObject).then(function(response) {
if(response.success) {
Notification.now.success(response.message);
$scope.loading = false;
} else {
Notification.now.error(response.message);
$scope.loading = false;
}
}, function(reason) {
Notification.now.error(reason.message);
$scope.loading = false;
});
};
If anyone can help me out I'd be eternally grateful. Thank you!
try adding novalidate in your form tag if this does not work dont use angular ui Form validation just use below format to validate .
<form name="pointsField" novalidate>
<input type="text" id="username" name="username" placeholder="Email Address"
ng-model="user.username" autocomplete="off" required >
<span class="text-danger" ng-show="pointsField.username.$dirty && pointsField.username.$invalid">
<span ng-show="pointsField.username.$error.required">Email Address is required</span>
</span>
<button type="submit" class="submit center" ng-disabled="pointsField.$invalid || dataLoading ">
<form>
I'm looking to create an HTML5 custom validation message when I enter 2 passwords which don't match.
Here's my HTML and JQuery
HTML:
<form class="form-group main-settings-form" id="main-settings-form-password">
<input class="form-control main-settings-form-input password-main" type="password" placeholder="Enter new password" id="new-password" pattern='(?=.*\d)(.{6,})' required>
<input class="form-control main-settings-form-input" type="password" placeholder="Retype new password" id="confirm-password" pattern='(?=.*\d)(.{6,})' required>
<div class="main-settings-form-buttons">
<button type="button" class="btn btn-danger settings-edit-cancel">Cancel</button>
<button class="btn btn-success" type="submit">Save</button>
<br>
<br>
Forgot password?
</div>
</form>
JS:
$(document).ready(function () { //This confirms if the 2 passwords match
$('#confirm-password').on('keyup', function (e) {
var pwd1 = $("#new-password").get(0);
var pwd2 = $("#confirm-password").get(0);
pwd2.setCustomValidity("");
if (pwd1 != pwd2) {
document.getElementById("confirm-password").setCustomValidity("The passwords don't match"); //The document.getElementById("cnfrm-pw") selects the id, not the value
}
else {
document.getElementById("confirm-password").setCustomValidity("");
//empty string means no validation error
}
e.preventDefault(); //would still work if this wasn't present
});
});
The problem is, the message is always triggered even if the passwords do match. Please help me trigger the message only when the passwords dont match, and be allowed to safely submit when they do.
JS fiddle: https://jsfiddle.net/kesh92/a8y9nkqa/
password requirements in the fiddle: 6 characters with atleast one number
jQuery get() returns the dom elements of each...they can never be equal
You want to compare values.
Try changing
if (pwd1 != pwd2) { //compare 2 dom nodes
To
if ( pwd1.value != pwd2.value) { //compare 2 dom node values
Note however that you also need to now consider empty values since you are over riding validty
The thing is, I already figured it out(just copy/paste some codes from stackoverflow). But the thing that only matters for me is; Whenever I enter cc number and hits "Tab", it automatically validates the expiration. I used onchange attribute for the 2 boxes. Please help me adjust my codes.
What i would like for the outcome is..
-When i enter cc number, and hit "Tab" the onchange attribute for cc textbox[validates it] and not yet validating the Expiration textbox[not yet validate].
I have tried everything but it only makes it not work..hehe.. Im sorry guys, im not really good at constructing javascripts. Thank you.
Javascript
<!-- START: VALIDATION IN CREDIT CARDS -->
<script type="text/javascript">
//START: FOR CREDIT CARD NUMBER
function validateCard(card_no){
var Check_MasterCard = /^([51|52|53|54|55]{2})([0-9]{14})$/;
var Check_Visa = /^([4]{1})([0-9]{12,15})$/;
if(Check_Visa.test(card_no)){
document.getElementById('cardSuccess').style.display = "block";
document.getElementById('cardSuccess_1').style.display = "none";
document.getElementById('cardError').style.display = "none";
return true;
}else if(Check_MasterCard.test(card_no)){
document.getElementById('cardSuccess_1').style.display = "block";
document.getElementById('cardSuccess').style.display = "none";
document.getElementById('cardError').style.display = "none";
return true;
}else{
document.getElementById('cardError').style.display = "block";
document.getElementById('cardSuccess_1').style.display = "none";
document.getElementById('cardSuccess').style.display = "none";
return false;
}
}
//END: FOR CREDIT CARD NUMBER
function validateForm(){
// Set error catcher
var error = 0;
// Validate Credit Card
if(!validateCard(document.getElementById('card_no').value)){
error++;
}
if(error > 0){
return false;
}
//FOR EXPIRY VALIDATION
var datereg = /^(0[1-9]|1[012])[- /.](19|20)\d\d+$/;
if (!datereg.test(document.getElementById('credit_card_exp').value)) {
document.getElementById("expiry_error1").style.display="block";
document.getElementById("expiry_error").style.display="none";
return false;
}
var currentDate = new Date(); //this returns the current datetime
//Clear all the other date parts.
currentDate.setDate(0);
currentDate.setHours(0);
currentDate.setMinutes(0);
currentDate.setSeconds(0);
currentDate.setMilliseconds(0);
var year = parseInt(payment_form.credit_card_exp.value.split('/')[1]);
var month = parseInt(payment_form.credit_card_exp.value.split('/')[0]);
var dateToCheck = new Date(year,month,0,0,0,0,0);
if (dateToCheck.getTime() < currentDate.getTime()){
//invalid date
document.getElementById("expiry_error").style.display="block";
document.getElementById("expiry_error1").style.display="none";
return false;
}
document.getElementById("expiry_error").style.display="none";
document.getElementById("expiry_error1").style.display="none";
return true;
//END FOR EXPIRY VALIDATION
}
</script>
<!-- END: VALIDATION IN CREDIT CARDS -->
HTML:
<form id='payment_form' name="payment_form" method="post" action="exec_order_process.php" onsubmit="return validateForm();">
Card Number*
<input class="form-control" onchange="return validateForm();" name="card_no" id="card_no" type="text" maxlength="16" required="required" placeholder="Enter Card number" >
<span class="alert alert-danger changeFont" id="cardError" style="display: none;">You must enter a valid Credit Card for VISA and MasterCard Only<span class="glyphicon glyphicon-remove"></span></span>
<span class="alert alert-success changeFont" id="cardSuccess" style="display: none;">This is a VISA card <span class="glyphicon glyphicon-ok"></span></span>
<span class="alert alert-success changeFont" id="cardSuccess_1" style="display: none;">This is a MasterCard <span class="glyphicon glyphicon-ok"></span></span>
Expiration*
<input onchange="return validateForm();" class="form-control" name="credit_card_exp" id="credit_card_exp" type="text" maxlength="7" onchange="validCCForm(this);" required placeholder="MM / YYYY ">
<label class="error" id="expiry_error" style="display: none;">Credit Card Expired</label>
<label class="error" id="expiry_error1" style="display: none;">Enter valid Date Format</label>
<input type="submit" value="Submit">
</form>
You will have to create 2 Javascript functions:
validateCreditCard and validateExpiration
Then you can use the validateCreditCard function on you credit card input (on change) and validateExpiration on the expiration input.
You can still keep a function validateForm, but this function will simply call the other 2 functions so that all inputs are validated (you can use it for example before submit).
The reason why the expiration date is being validated when the card number input element loses focus is that the onchange attribute of that element calls ValidateForm() which is where you are validating the expiration date.
Refactor the expiration date validation code to a unique function (Single Responsibility Principal).
Remove the duplicate onchange attribute from the credit_card_exp html input element
Refactor the onchange attributes of your input elements as follows:
<label>Card Number*</label>
<input onchange="validateCardNumber(this.value)" class="form-control" name="card_no" id="card_no" type="text" maxlength="16" required="required" placeholder="Enter Card number" />
<label>Expiration*</label>
<input onchange="validateExpirationDate(this.value)" class="form-control" name="credit_card_exp" id="credit_card_exp" type="text" maxlength="7" required placeholder="MM / YYYY " />
You may like to review the HTML onchange Attribute and JavaScript/HTML Event pages on w3Schools.com website for clarification.
I am trying to save an HTML field (for later use in a form) from a JS script.
This is the code:
Form
<form class="new_client" id="new_client" action="/clients" accept-charset="UTF-8" method="post">
<div class="form-group">
<input class="form-input" type="hidden" name="client[city]" id="client_city">
</div>
<div class="form-group">
<input class="form-input" type="hidden" name="client[address]" id="client_address">
</div>
<div id="locationField">
<input autocomplete="off" class="autocomplete" placeholder="Enter your address" type="text">
</div>
<div class="text-center">
<button class="btn button-general ">Save</button>
</div>
</form>
And the javascript:
function configureGeoAutocomplete(context) {
if( context === undefined ) {
context = $('body');
}
var element = context.find('.autocomplete')
//It doesn't really matter what this line does, it's from Google Places API
var autocomplete = new google.maps.places.Autocomplete(
element[0], {types: ['geocode']});
autocomplete.addListener('place_changed', fillInAddress)
}
function fillInAddress() {
var client_address = autocomplete.getPlace().formatted_address;
document.getElementById("client_address").value = client_address;
}
The javascript is queried when loading the modal in which the form is
jQuery(function() {
$('div.modal').on('loaded.bs.modal', function(e) {
configureGeoAutocomplete(context);
}
}
I wanna save that client_address to the text field so when the form is submitted I can have that information.
Sounds like an excellent candidate for cookies if you are allowed to use them: http://www.w3schools.com/js/js_cookies.asp. Another idea is to pass it along in a Query String. It isn't PII or anything like that. Try an event code on that input. I do not like to hit "enter"!
onkeypress="if (event.keycode==13) { // do something }"
Handle the form submit event:
$(function() {
$("#new_client").submit(function(e) {
e.preventDefault();
// This is your value stored in the field.
$("#client_address").val();
});
})
Apparently, for some reason, if I searched the element by ID it was not saving the information on the field. If I istead search by class:
function fillInAddress() {
var place = autocomplete.getPlace();
$(".client-address").val(place.formatted_address);
}
It works as intended.
I am using jQuery Mobile and am attempting to use HTML5 form field validation to perform inline form field validation. I am doing this because I really like the way that the browser reports issues in the bubble and I don't think it is very user friendly to wait until someone has completed filling out a form and then tell them what is wrong. Here is my HTML:
<form id="frmMain" action="#">
<input type="checkbox" data-enhance="false" value="1" id="cbxFB" />
<label for="cbxFB">
<span class="formsubtext">Check this box to use Facebook information to help fill out this registration. Once registered you will be able to use the Facebook login button.</span>
</label>
<label for="tbEmail">*Email</label><input type="email" id="tbEmail" required autofocus placeholder="example#address.com" />
<label for="tbPassword">*Password</label><input type="password" id="tbPassword" required />
<div class="formsubtext" style="margin-top:1px; padding-top:0px; margin-bottom:10px">Minimum of 6 characters, one capital character, and one lower case character.</div>
<label for="tbPasswordConfirm">*Password Confirm</label><input type="password" id="tbPasswordConfirm" required />
<label for="tbPin">*Account Pin</label><input type="password" pattern="[0-9]{4}" id="tbPin" required placeholder="####" />
<div class="formsubtext" style="margin-top:1px; padding-top:0px; margin-bottom:10px">A four digit number that you will remember. This value will be needed to perform sensitive tasks within the application.</div>
<label for="tbFName">*First Name</label><input type="text" id="tbFName" required />
<label for="tbLName">*Last Name</label><input type="text" id="tbLName" required />
<label for="tbPhone">Phone Number</label><input type="tel" id="tbPhone" pattern="\d{3}[\-]\d{3}[\-]\d{4}" placeholder="###-###-####" style="margin-bottom:1px; padding-bottom:0px;" />
<div class="formsubtext" style="margin-top:1px; padding-top:0px; margin-bottom:20px;">Used at your option when you schedule an appointment with a service provider</div>
<div style="display:none;"><label for="tbfbID">Facebook ID</label><input type="text" id="tbfbID" /></div>
<input type="submit" id="btnMainNext" data-icon="arrow-r" data-iconpos="right" value="Next" data-theme="c" class="ui-btn-c ui-btn ui-corner-all" />
</form>
For the confirm password form field I have the following event defined:
$("#tbPasswordConfirm").on("change", function (event) {
var password = $("#tbPassword").val();
var passwordconfirm = $("#tbPasswordConfirm").val();
if (password != passwordconfirm) {
$("#tbPasswordConfirm")[0].setCustomValidity("The value entered does not match the previous password entered.");
$("#btnMainNext").click();
}
else {
$("#tbPasswordConfirm")[0].setCustomValidity("");
}
$(this).focus().select();
})
My problem is that when the user enters something into the field and moves to the next field the HTML form validation shows the error message for the next field (which is required). I want it to show the message for the field they just left. How do I stop the focus from moving to the next field so that the bubble message that shows up is from the field they just entered the data into? As you can see I have tried setting the focus but that does not work. Any help would be greatly appreciated.
You can stop focus from moving to the next field but you can't trigger native validation UI or error message unless you click submit button.
To stop focus from moving next field, after you set the custom validity on the field, you can use:
$('#tbPasswordConfirm').blur(function(event) {
event.target.checkValidity();
}).bind('invalid', function(event) {
setTimeout(function() { $(event.target).focus();}, 50);
});
The blur() function will check the validity on blur and if it would be invalid, the corresponding function in bind() would set the focus back to that element.
Solved it
Fiddle
$(function() {
$("#tbPasswordConfirm").on("input", function(event) {
var thisField = $("#tbPasswordConfirm")[0],
theForm = $("#frmMain")[0],
password = $("#tbPassword").val(),
passwordconfirm = $(this).val(),
custom = password === passwordconfirm ? "" : "The value entered does not match the previous password entered.";
thisField.setCustomValidity(custom);
if (!theForm.checkValidity()) theForm.reportValidity();
});
});
You can use html tabindex attr to manipulate which element will get the focus when you click tab character. See docs to how to use it.
For example, if you make your password confirm input as tabindex="5", you can add tabindex="6" to the <label for="tbPin"> element to prevent next input from focusing right after.