Manually Triggering Form Validation using jQuery - html

I have a form with several different fieldsets. I have some jQuery that displays the field sets to the users one at a time. For browsers that support HTML5 validation, I'd love to make use of it. However, I need to do it on my terms. I'm using JQuery.
When a user clicks a JS Link to move to the next fieldset, I need the validation to happen on the current fieldset and block the user from moving forward if there is issues.
Ideally, as the user loses focus on an element, validation will occur.
Currently have novalidate going and using jQuery. Would prefer to use the native method. :)

TL;DR: Not caring about old browsers? Use form.reportValidity().
Need legacy browser support? Read on.
It actually is possible to trigger validation manually.
I'll use plain JavaScript in my answer to improve reusability, no jQuery is needed.
Assume the following HTML form:
<form>
<input required>
<button type="button">Trigger validation</button>
</form>
And let's grab our UI elements in JavaScript:
var form = document.querySelector('form')
var triggerButton = document.querySelector('button')
Don't need support for legacy browsers like Internet Explorer? This is for you.
All modern browsers support the reportValidity() method on form elements.
triggerButton.onclick = function () {
form.reportValidity()
}
That's it, we're done. Also, here's a simple CodePen using this approach.
Approach for older browsers
Below is a detailed explanation how reportValidity() can be emulated in older browsers.
However, you don't need to copy&paste those code blocks into your project yourself — there is a ponyfill/polyfill readily available for you.
Where reportValidity() is not supported, we need to trick the browser a little bit. So, what will we do?
Check validity of the form by calling form.checkValidity(). This will tell us if the form is valid, but not show the validation UI.
If the form is invalid, we create a temporary submit button and trigger a click on it. Since the form is not valid, we know it won't actually submit, however, it will show validation hints to the user. We'll remove the temporary submit button immedtiately, so it will never be visible to the user.
If the form is valid, we don't need to interfere at all and let the user proceed.
In code:
triggerButton.onclick = function () {
// Form is invalid!
if (!form.checkValidity()) {
// Create the temporary button, click and remove it
var tmpSubmit = document.createElement('button')
form.appendChild(tmpSubmit)
tmpSubmit.click()
form.removeChild(tmpSubmit)
} else {
// Form is valid, let the user proceed or do whatever we need to
}
}
This code will work in pretty much any common browser (I've tested it successfully down to IE11).
Here's a working CodePen example.

You can't trigger the native validation UI (see edit below), but you can easily take advantage of the validation API on arbitrary input elements:
$('input').blur(function(event) {
event.target.checkValidity();
}).bind('invalid', function(event) {
setTimeout(function() { $(event.target).focus();}, 50);
});
The first event fires checkValidity on every input element as soon as it loses focus, if the element is invalid then the corresponding event will be fired and trapped by the second event handler. This one sets the focus back to the element, but that could be quite annoying, I assume you have a better solution for notifying about the errors. Here's a working example of my code above.
EDIT: All modern browsers support the reportValidity() method for native HTML5 validation, per this answer.

In some extent, You CAN trigger HTML5 form validation and show hints to user without submitting the form!
Two button, one for validate, one for submit
Set a onclick listener on the validate button to set a global flag(say justValidate) to indicate this click is intended to check the validation of the form.
And set a onclick listener on the submit button to set the justValidate flag to false.
Then in the onsubmit handler of the form, you check the flag justValidate to decide the returning value and invoke the preventDefault() to stop the form to submit. As you know, the HTML5 form validation(and the GUI hint to user) is preformed before the onsubmit event, and even if the form is VALID you can stop the form submit by returning false or invoke preventDefault().
And, in HTML5 you have a method to check the form's validation: the form.checkValidity(), then in you can know if the form is validate or not in your code.
OK, here is the demo:
http://jsbin.com/buvuku/2/edit

var field = $("#field")
field.keyup(function(ev){
if(field[0].value.length < 10) {
field[0].setCustomValidity("characters less than 10")
}else if (field[0].value.length === 10) {
field[0].setCustomValidity("characters equal to 10")
}else if (field[0].value.length > 10 && field[0].value.length < 20) {
field[0].setCustomValidity("characters greater than 10 and less than 20")
}else if(field[0].validity.typeMismatch) {
field[0].setCustomValidity("wrong email message")
}else {
field[0].setCustomValidity("") // no more errors
}
field[0].reportValidity()
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="email" id="field">

Somewhat easy to make add or remove HTML5 validation to fieldsets.
$('form').each(function(){
// CLEAR OUT ALL THE HTML5 REQUIRED ATTRS
$(this).find('.required').attr('required', false);
// ADD THEM BACK TO THE CURRENT FIELDSET
// I'M JUST USING A CLASS TO IDENTIFY REQUIRED FIELDS
$(this).find('fieldset.current .required').attr('required', true);
$(this).submit(function(){
var current = $(this).find('fieldset.current')
var next = $(current).next()
// MOVE THE CURRENT MARKER
$(current).removeClass('current');
$(next).addClass('current');
// ADD THE REQUIRED TAGS TO THE NEXT PART
// NO NEED TO REMOVE THE OLD ONES
// SINCE THEY SHOULD BE FILLED OUT CORRECTLY
$(next).find('.required').attr('required', true);
});
});

I seem to find the trick:
Just remove the form target attribute, then use a submit button to validate the form and show hints, check if form valid via JavaScript, and then post whatever. The following code works for me:
<form>
<input name="foo" required>
<button id="submit">Submit</button>
</form>
<script>
$('#submit').click( function(e){
var isValid = true;
$('form input').map(function() {
isValid &= this.validity['valid'] ;
}) ;
if (isValid) {
console.log('valid!');
// post something..
} else
console.log('not valid!');
});
</script>

Html Code:
<form class="validateDontSubmit">
....
<button style="dislay:none">submit</button>
</form>
<button class="outside"></button>
javascript( using Jquery):
<script type="text/javascript">
$(document).on('submit','.validateDontSubmit',function (e) {
//prevent the form from doing a submit
e.preventDefault();
return false;
})
$(document).ready(function(){
// using button outside trigger click
$('.outside').click(function() {
$('.validateDontSubmit button').trigger('click');
});
});
</script>
Hope this will help you

For input field
<input id="PrimaryPhNumber" type="text" name="mobile" required
pattern="^[789]\d{9}$" minlenght="10" maxLength="10" placeholder="Eg: 9444400000"
class="inputBoxCss"/>
$('#PrimaryPhNumber').keyup(function (e) {
console.log(e)
let field=$(this)
if(Number(field.val()).toString()=="NaN"){
field.val('');
field.focus();
field[0].setCustomValidity('Please enter a valid phone number');
field[0].reportValidity()
$(":focus").css("border", "2px solid red");
}
})

$('#id').get(0).reportValidity();
This will trigger the input with ID specified. Use ".classname" for classes.

When there is a very complex (especially asynchronous) validation process, there is a simple workaround:
<form id="form1">
<input type="button" onclick="javascript:submitIfVeryComplexValidationIsOk()" />
<input type="submit" id="form1_submit_hidden" style="display:none" />
</form>
...
<script>
function submitIfVeryComplexValidationIsOk() {
var form1 = document.forms['form1']
if (!form1.checkValidity()) {
$("#form1_submit_hidden").click()
return
}
if (checkForVeryComplexValidation() === 'Ok') {
form1.submit()
} else {
alert('form is invalid')
}
}
</script>

Another way to resolve this problem:
$('input').oninvalid(function (event, errorMessage) {
event.target.focus();
});

Related

What is the HTML <dialog> tag used for and when to use it?

The way I've understood it, the tag is used to open and close content like a popup alert. What I fail to understand is what advantages the tag has compared to just using a "div" and styling it with css and adding functionality to it with js. It also seems counter intuitive to manipulate the "open" property in order to show/hide the content instead of using display:none/block; with css.
I also don't understand exactly which scenarios would be considered a dialog box. Is a form login box a dialogbox? What about a popup telling you to disable adblock? Are all popups that can be hidden considered dialog boxes?
The traditional, hacky way to create a dialog, via designing a div via CSS only seems to be intuitive for you because you are used to it. However, you need to implement every functionality related to it, such as:
opening it
closing it
Also, in the future, this will be enhanced by standard functionalities, so, while it's not urgent for already existent code, but when you write code, especially when you start a project, it makes sense to start using it. Let's see an example from [Mozilla's page][1]:
var updateButton = document.getElementById('updateDetails');
var favDialog = document.getElementById('favDialog');
var outputBox = document.querySelector('output');
var selectEl = document.querySelector('select');
var confirmBtn = document.getElementById('confirmBtn');
// "Update details" button opens the <dialog> modally
updateButton.addEventListener('click', function onOpen() {
if (typeof favDialog.showModal === "function") {
favDialog.showModal();
} else {
alert("The <dialog> API is not supported by this browser");
}
});
// "Favorite animal" input sets the value of the submit button
selectEl.addEventListener('change', function onSelect(e) {
confirmBtn.value = selectEl.value;
});
// "Confirm" button of form triggers "close" on dialog because of [method="dialog"]
favDialog.addEventListener('close', function onClose() {
outputBox.value = favDialog.returnValue + " button clicked - " + (new Date()).toString();
});
<!-- Simple pop-up dialog box containing a form -->
<dialog id="favDialog">
<form method="dialog">
<p><label>Favorite animal:
<select>
<option></option>
<option>Brine shrimp</option>
<option>Red panda</option>
<option>Spider monkey</option>
</select>
</label></p>
<menu>
<button value="cancel">Cancel</button>
<button id="confirmBtn" value="default">Confirm</button>
</menu>
</form>
</dialog>
<menu>
<button id="updateDetails">Update details</button>
</menu>
<output aria-live="polite"></output>
However, at the time of this writing (February the 3rd, 2022), this is not supported in all browsers, so it is perfectly feasible to avoid using it for now, until it will become supported everywhere.
[1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog

Empty action attribute on a form with angularJS

I'm trying to submit a form the normal way in a AngularJS application but I encounter an issue : it seems that I must specify the action attribute.
According to the HTML specifications (http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#form-submission-algorithm) :
If action is the empty string, let action be the document's address of
the form document.
But AngularJS refuses to submit the form if the action attribute is not filled.
A work-around I found would be to use action="#" but this is not an acceptable solution since I might use the hash and I don't want it to be rewritten.
Has anyone ever experienced this issue ?
Edit : I don't want to use angular for this form, I just want to submit it the "old" way
I created a small directive to solve this:
.directive('form', ['$location', function($location) {
return {
restrict:'E',
priority: 999,
compile: function() {
return {
pre: function(scope, element, attrs){
if (attrs.noaction === '') return;
if (attrs.action === undefined || attrs.action === ''){
attrs.action = $location.absUrl();
}
}
}
}
}
}]);
Seems to be good for me. It looks for a form where the action is empty, and sets it to the current url.
Actually, it doesn't set the action - it sets the attr value, so the actual form directive thinks it's got one.
Update by #Reimund is good - I have actually had to do the same.
New Update - I have added the option to add a noaction attribute to the form element; this enables you to return to a "normal" angular situation. Otherwise this directive will submit forms twice if using ajax.
In the library, you can see that Angular listens to the event submit of your forms without action : https://github.com/angular/angular.js/blob/b9fa5c5a6781f4e1ec337f27d55c69db491a6555/src/ng/directive/form.js#L331
You can comment this line, it works, but I'm against editing the code of libraries.
Few lines after, you can see that Angular listening to the event $destroy enabling to remove the action on this event.
Therefore, to avoid modifying Angular, you can just trigger this event of your form:
angular.element(document).ready(function(){
angular.element(document.querySelector("#loginForm")).triggerHandler("$destroy")‌​;
});
The reason of this behavior is described few lines above:
we can't use jq events because if a form is destroyed during submission the default action is not prevented.
And the related issue is: https://github.com/angular/angular.js/issues/1238
You can use ng-submit.
Form
<form name="test" action="" ng-submit="submit()">
What's your name? <input ng-model="name" /><br />
<button>Send</button>
</form>
<br />
My name is: {{name}}
JS
var app = angular.module('App', []);
app.controller('AppCtrl', function($scope) {
$scope.submit = function() {
$scope.name = $scope.name + ' Doe';
}
});
Plunker http://plnkr.co/edit/rqAwxWmozrzwwj4oAU5k?p=preview
Normally I simply make button with ng-click handler.
<button ng-click="Generate()">Submit</button><br>

javascript/jQuery Double Submit Prevention method disables initiation of html5 attributes (e.g. Required, Pattern, etc.)

The javascript/jQuery double submit prevention method I use is this:
$("#btnsubmit").click(function () {
$("#btnsubmit").attr('disabled','disabled');
$('#postform').submit();
});
So on submit click, the Submit Button is disabled and the form is submit. So double submit of the form will not happen. BUT. The problem now is that the html5 attributes will not initiate (e.g. Required, Pattern, etc.)
Does anyone have any ideas on how to fix this?
or maybe you can suggest alternative double submit prevention method that will not tamper with the html5 attributes?
EDIT + DANIEL PATZ ANSWER:
$('#postform').on('submit', function (e) {
// THIS PART
var titleLength = $("#title").val().length;
var descriptionLength = $("#description").val().length;
if(titleLength < 20 || descriptionLength < 150) {
$("#ps").text("Title and Desc Problem.");
} else {
// UNTIL HERE
$('[type="submit"]').prop('disabled','disabled');
}
});
If you catch the submit event, it should work. http://jsfiddle.net/tcc7u/
HTML:
<form>
<input required /><br />
<input type="submit" />
</form>
JS:
$('form').on('submit', function (e) {
$('[type="submit"]').prop('disabled','disabled');
});

html5 form checkValidity() method not found

I am trying to use the form method checkValidity().
http://html5test.com/ tells me that my browser (Chrome) support the form-level checkValidity method.
However, using jsfiddle http://jsfiddle.net/LcgnQ/2/ I have tried the following html and javascript snippets:
<form id="profileform" name="profileform">
<input type="text" id="firstname" required>
<input type="button" id="testbutton" value="Test">
</form>
$('#testbutton').bind('click',function(){
try{
alert($('#profileform').checkValidity());
}
catch(err){alert('err='+err)};
});
I'm getting an error: object has no method checkValidity()
What am I doing wrong?
Try:
$('#profileform')[0].checkValidity()
When you select $('#profileform') you get a jQuery object array. To access actual DOM properties you must select the first item in the array, which is the raw DOM element.
#robertc 's Answer is perfect. Anyway I'd just add another way to do it using jQuery's .get([index]) function. It also retrieves the DOM element for the given index, or all of the matched DOM elements if there's no index declared.
In the end it is exactly the same, only written in a bit more verbose way:
$('#profileform').get(0).checkValidity()
Leaving you the docs right here: https://api.jquery.com/get/
Just another way:
// Fetch all the forms we want to apply custom Bootstrap validation styles to
var forms = document.getElementsByName('profileform');
// Loop over them and prevent submission
var validation = Array.prototype.filter.call(forms, function (form) {
form.addEventListener('submit', function (event) {
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
}, false);
});

How can I can set which submit button is fired on enter?

I have a form with several submit buttons. I want my last button to handle the submit rather than the HTML5 spec'ed first button.
I can't change the html at this point and am fairly sure this requires JS. But when I've given it a shot I've gotten into nasty loops or dead code trying to prevent default behaviour and then fire my other button.
Has anyone done this before? jQuery is on the page if needed.
Thanks,
Denis
Since you mentioned jQuery :)
If all you want to do is submit your form when a user presses the enter key, then
$(function() {
$('body').keypress(function(e) {
if (e.which == 13) {
e.preventDefault();
$('#myForm').submit();
}
});
});
However, if you have different behavior/forms depending on which button is clicked and you want the enter key to trigger your last button's click event, then
$(function() {
$('body').keypress(function(e) {
if (e.which == 13) {
e.preventDefault();
$('input[type="submit"]:last').click();
}
});
});
You should just change the input element's type attribute to button instead when you don't want it to submit the form. (I know you said you can't really change the HTML, but this is the best way)
<input type="button" name="mybutton" class="submit-button" value="I wont submit!" />
jQuery code:
$('.submit-button').click(function() {
$('#secret-value-field').val($(this).val());
$(this).parents('form').submit();
});
Or something along those lines.