Using HTML form field validation - javascript

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.

Related

Remove error validation message when user clicks/moves out of the textbox

I am working on a reactive form in angular. Facing this problem where a field that is not required should have some validations when it is dirty or touched but as soon as the user is out of this textbox/field, the validation message should just go away. I have tried using ng-invalid but it is not working as the field when loaded for the first time is having ng-invalid class. The following is the code -
<div class="form-group">
<label>Street Name</label>
<input type="text" class="form-control" formControlName="streetName">
<span class="text-danger"
*ngIf="registerForm.get('streetName').touched || registerFormControl.get('streetName').dirty" class="Required">
<span *ngIf="registerForm.get('streetName').error?.pattern || registerForm.get('streetName').error?.minLength">
Pattern & Minlength error
</span>
<span class="text-danger"
*ngIf="registerForm.get('streetName').error?.monthError || registerForm.get('streetName').error?.otherError">
Month and Other Error
</span>
</span>
</div>
FormGroup Validation -
streetName:['',{
Validators: [
Validators.pattern(0-9),
Validators.minLength(9),
this.customValidations.streetValid
],
updateOn: 'blur'
}]
How do I get this validation dissappear?
You can use the focus and blur events to track if and when a user is in an input field or not.
<input (focus)="onFocus()" (blur)="onBlur()">
In this code example onFocus() is called when the user clicks/is-in the input box. onBlur() is called when the user clicks out of the input box.
We can use this to better distinguish if we should display the error message or not.
Let's say you have two inputs: Street Name and Street Address. We will create an onFocus() function that handles which item is focused and an onBlur() function that will clear the focused selection.
// Class variables
public selectedField = "";
function onFocus(identifier : string) {
selectedField = identifier; // set the field
}
function onBlur() {
selectedField = ""; // clear the field
}
Now, on our inputs:
<input (focus)="onFocus('streetName')" (blur)="onBlur()" type="text" class="form-control" formControlName="streetName">
<input (focus)="onFocus('streetAddress')" (blur)="onBlur()" type="text" class="form-control" formControlName="streetAddress">
Finally, we can handle if we should display the error message or not. All we need to do is add one more condition to the *ngIf of the error span.
<!--Example Street Name Error Span -->
<span class="text-danger" *ngIf="selectedField == 'streetName' && . . . ">
Invalid Street Name
</span
<!--Example Street Address Error Span -->
<span class="text-danger" *ngIf="selectedField == 'streetAddress' && . . . ">
Invalid Street Address
</span
If you'd like a better understanding on how focus works, you can find it here.

Form Validation Not Resetting After Failing Validation

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('')"/>

Adding input elements to the DOM using jQuery

I am programming a web application which accepts barcodes from a barcode reader in an input field. The user can enter as many barcodes that s/he wants to (i.e. there is no reason for a predefined limit). I have come up with a brute force method which creates a predefined number of hidden input fields and then reveals the next one in sequence as each barcode is entered. Here is the code to do this:
<form id="barcode1" name="barcode" method="Post" action="#">
<div class="container">
<label for="S1">Barcode 1 &nbsp </label>
<input id="S1" class="bcode" type="text" name="S1" onchange="packFunction()" autofocus/>
<label for="S2" hidden = "hidden">Barcode 2 &nbsp </label>
<input id="S2" class="bcode" type="text" hidden = "hidden" name="S2" onchange="packFunction()" />
<label for="S3" hidden = "hidden">Barcode 3 &nbsp </label>
<input id="S3" class="bcode" type="text" hidden = "hidden" name="S3" onchange="packFunction()" />
<label for="S4" hidden = "hidden">Barcode 4 &nbsp </label>
<input id="S4" class="bcode" type="text" hidden = "hidden" name="S4" onchange="packFunction()" />
<label for="S5" hidden = "hidden">Barcode 5 &nbsp </label>
<input id="S5" class="bcode" type="text" hidden = "hidden" name="S5" onchange="packFunction()" />
</div>
<div class="submit">
<p><input type="submit" name="Submit" value="Submit"></p>
</div>
</form>
<script>
$(function() {
$('#barcode1').find('.bcode').keypress(function(e){
// to prevent 'enter' from submitting the form
if ( e.which == 13 )
{
$(this).next('label').removeAttr('hidden')
$(this).next('label').next('.bcode').removeAttr('hidden').focus();
return false;
}
});
});
</script>
This seems to be an inelegant solution. It would seem to be better to create a new input field after each barcode has been entered. I have tried creating new input elements in the DOM using jQuery, and I can get the new input element to show. But it uses the onchange event, which detects changes in the original input field. How do I transfer focus and detect onchange in the newly created input field? Here is the code that I have played with to test out the idea:
<div>
<input type="text" id="barcode" class="original"/>
</div>
<div id="display">
<div>Placeholder text</div>
</div>
<script src="./Scripts/jquery-2.2.0.min.js"></script>
$(function () {
$('#barcode').on('change', function () {
$('#display').append('<input id='bcode' class='bcode' type='text' name='S1' autofocus/>')
});
});
</script>
Once I have these barcodes, I pack them into array which I then post them to a server-side script to run a mySQL query to retrieve data based on the barcodes, and then post that back to the client. So part of what I have to achieve is that each barcode that is entered into the different input fields need to be pushed into an array.
Is there an elegant way to accomplish the creation of input fields dynamically and then detecting changes in those to create yet more input fields?
The dynamic update you have tried out is all right. If you must push it into an array on submit you have to prevent default of form submit, serialize the form and then make an ajax request.
Heres an example:
$('form').on('submit',function(e){
e.preventDefault();
var formData = $(this).serializeArray();//check documentation https://api.jquery.com/serializeArray/ for more details
$.ajax({
type:'post',
url:<your url>//or you could do $('form').attr('action')
data:formData,
success:function(){}//etc
})
});
If you do not display the barcodes in the html you can skip the input fields and store the read barcodes in an array[]. Not everything that happens in javascript has to be displayed in the website (View) . i do not know what code you use to scan the barcode but you do not need the input-elements at all.
See the example on this site https://coderwall.com/p/s0i_xg/using-barcode-scanner-with-jquery
instead of console.log() the data from the barcode scanner can simply be saved in an array[] and be send from there.
If you want to create elements dynamcially see this thread: dynamically create element using jquery
The following code adds the p-element with the label "Hej" to the div "#contentl1"
`$("<p />", { text: "Hej" }).appendTo("#contentl1");`
UPDATE: I added some simple CSS to make each input field display on its own line.
Here's one strategy:
Listen for the enter/return key on the input box.
When the enter/return key is pressed (presumably after entering a barcode), create a new input box.
Stop listening for the enter key on the original input and start listening for it on the new input.
When a "submit all" button is pressed (or when tab is used to shift the focus from the most recent input to the "submit all" button and enter is pressed), then collect all the input values in an array.
$(function() {
var finishBarcode = function(evt) {
if (evt.which === 13) {
$(evt.target).off("keyup");
$("<input class='barcode' type='text'/>")
.appendTo("#barcodes")
.focus()
.on("keyup", finishBarcode);
}
};
var submitBarcodes = function(evt) {
var barcodesArr = $(".barcode").map(function() {
return $(this).val();
}).get();
$("#display").text("Entered Barcodes: " + barcodesArr);
};
var $focusedInput = $('.barcode').on("keyup", finishBarcode).focus();
var $button = $('#submitAll').on("click", submitBarcodes);
});
input.barcode {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>Type barcode into input box</li>
<li>To enter barcode and allow new entry, press Return</li>
<li>To submit all barcodes, either press tab and then return or click Submit button</li>
</ul>
<div id="barcodes"><input type="text" class="barcode" /></div>
<div><button id="submitAll">Submit all barcodes</button></div>
<div id="display">Placeholder text</div>

Do not trigger form.$invalid on first load

Having such form
<div ng-controller="FormController as f_ctrl">
<form ng-submit="f_ctrl.submit()" name="myForm">
<input type="text" ng-model="f_ctrl.user.username"
required
ng-minlength="4"/>
<input type="text" ng-model="f_ctrl.user.password"/>
<input type="submit" value="Submit" ng-disabled="myForm.$invalid">
</form>
</div>
and such controller
.controller('FormController', [function() {
var self = this;
self.submit = function() {
console.log('User submitted form with ' + self.user.username)
}
}]);
I have a problem: when page first loads it immediately shows red border on username field, even before I start typing anything.
I need to highlight invalid fields only after first submission. Can this be done using form.$invalid ?
You have to use $pristine for that. It is true when form controller is not changed. so when you change textbox data its comes false.
Small example for you.
<div class="form-group" ng-class="{ 'has-error' : userForm.password.$invalid && !userForm.password.$pristine }">
<input id="passAnime" type="password" name="password" ng-model="user.password" class="form-control input-md" placeholder="Password" tabindex="5" ng-maxlength="25" ng-minlength="6" required>
<span ng-show="userForm.password.$dirty && userForm.password.$invalid">
<p ng-show="userForm.password.$error.required" class="error-messages">
Your password is required.
</p>
<p ng-show="userForm.password.$error.minlength" class="error-messages">
Your password is too short. Minimum 6 chars.
</p>
<p ng-show="userForm.password.$error.maxlength" class="error-messages">
Your password is too long. Maximum 25 chars.
</p>
</span>
</div>
Angular has helpers that tell you if the form (or form field) is $dirty (user has typed something) or if the form is $touched (the blur event has been triggered on the input). See this demo.
I need to highlight invalid fields only after first submission.
Unfortunately, Angular doesn't support that. But you could implement it yourself rather easily:
Controller
function FormController() {
var vm = this;
vm.submitAttempted = false;
vm.submit = function(isValid) {
if (isValid) {
// do stuff
}
else {
vm.submitAttempted = true;
}
};
}
HTML
<div ng-app='app'>
<div ng-controller='FormController as vm'>
<form name='fooForm' ng-submit='vm.submit(fooForm.$valid)' novalidate>
<label>Username</label>
<input
name='username'
type='text'
ng-model='vm.user.username'
required
ng-minlength='4'
ng-class="{'invalid': vm.submitAttempted && fooForm.username.$invalid}">
<br /><br />
<button type='submit'>Submit</button>
</form>
</div>
</div>
CSS
.invalid {
border-color: red;
}
Demo
I have a problem: when page first loads it immediately shows red border on username field, even before I start typing anything.
That's probably because you have the following CSS class:
.ng-invalid {
border-color: red;
}
Angular will always apply the ng-invalid class to fields that are invalid, and there's nothing you could do about that. So if you don't always want invalid fields to have a red border, you can't use that class and you should do it in a way similar to what I proposed above.
Also, check out ngMessages.
You can disable the default styling on the input field that is adding the red border by default, by adding the following CSS:
input:required {
-moz-box-shadow: none;
box-shadow: none;
}
Then if you want to highlight the field when the form is submitted, you will need to ensure that the form and form fields have relevant name attributes. Doing this will allow you to check if the field is valid or not and apply a class to your text field when it is invalid:
<input type="text" name="username" ng-class="{ 'invalid-field' : f_ctrl.myForm.username.$invalid && !f_ctrl.myForm.username.$pristine }" required />
f_ctrl.myForm and f_ctrl.myform.username will have additional properties that you can use/check to determine if the form or fields are invalid or not, or if they have been modified at any point (e.g. f_ctrl.myform.username.$dirty). You should be able to view these properties on your page by adding the follow HTML:
<div>
<pre>{{f_ctrl.myForm | json}}</pre>
</div>
Or, you could output self.myForm to the console from your controller to view it's properties
console.log(self.myForm);

Make hidden div and inputs optional for valid form submit with jquery.validate

I have a form that may only be one page or may be two pages depending on whether it is a single individual or two people applying. What I am doing right now is enabling a link that allows the user to get to the next group of form elements for their co-applicant via an onchange event that shows the link that will slideToggle the first users inputs and show the inputs for the additional users. It's a pretty lengthy form so I cut it down to a few elements so I could fiddle it out:
Das Fiddle is here
<form method="POST" id="refiLoanForm" action="mailto:i#i.com">
<!--START PRIMARY APPLICANT -->
<div id="primary-applicant">
<label>
Application Type
<select name="applicationType" id="applicationType" class="wider" required>
<option value="individual">Individual</option>
<option value="joint">Joint</option>
</select>
</label>
<br>
<label for="loan-amount" id="loan-amount-label">Requested Finance Amount
<input type="text" id="loan-amount" name="loanAmount" required/></label>
<br>
<label for="remaining-term">Current Loan Remaining Term
<input type="text" id="remaining-term" name="remainingTerm" max="3" size="3" required class="override"/>
</label>
<br>
CONTINUE TO CO-APPLICANT
</div>
<!--END PRIMARY APPLICANT -->
<!--START CO_APPLICANT -->
<div id="co-applicant" style="display: none">
Back to Primary Applicant
<br>
<label for="co-first-name">First Name
<input type="text" id="co-first-name" name="coApplicantGivenName" maxlength="32" required/>
</label>
<br>
<label for="co-last-name">Last Name
<input type="text" id="co-last-name" name="coApplicantFamilyName" maxlength="32" required/>
</label>
</div>
JS:
$('#refiLoanForm').validate({
onkeyup: false,
ignore: ":disabled",
submitHandler: function (form) { // for demo
alert('valid form');
return false;
}
});
$("#singleSubmitBtnLoan").bind('click', function () {
$('#refiLoanForm').valid();
});
//Handle the content being shown
$("#singleSubmitBtnLink2").on('click', function () {
$("#primary-applicant").slideToggle("slow");
$("#co-applicant").slideToggle("slow");
});
$("#backToPrimary").on('click', function () {
$("#primary-applicant").slideToggle("slow");
$("#co-applicant").slideToggle("slow");
});
$('#applicationType').on('change', function() {
if ($(this).val() === 'joint') {
$('.primaryApplicantSwitch').slideToggle("slow");
$('.jointApplicantSwitch').slideToggle("slow");
} else {
$('.primaryApplicantSwitch').slideToggle("slow");
$('.jointApplicantSwitch').slideToggle("slow");
}
});
So in theory, the user can enter the fields and hit submit and the form is either valid or throws some errors. Or, the user can add a co-applicant, and validate the form on the link click before toggling to the next group of inputs.
Any ideas on how I would bind all of this to the one button and get it to play nice with jquery.validate?
You cannot dynamically "toggle" the rules of input fields.
However, you can use the .rules() method to dynamically add/change/remove rules, which essentially mimics the behavior of a toggle.
Also, since you're talking about fields that are hidden, you'll need to disable the option that makes validation ignore all hidden fields.
ignore: []

Categories