jQuery Validate using onclick handler not validating fields? - javascript

I want to use an onlick event handler to validate some form fields using jquery Validate. To do this I have the following code:
<input type="text" id="Name" name="Name">
<a class="btn btn-primary js-add-names" href="#">Add Names</a>
<input type="text" id="Age" name="Age">
<a class="btn btn-primary js-add-ages" href="#">Add Age</a>
<script>
$(".js-add-names").click(function (e) {
e.preventDefault();
$("form").validate({
rules: {
Name: {
required: true
}
},
messages: {
Name: "The Name is required"
}
});
if (!$("form").valid()) {
return;
}
// otherwise do stuff but we dont want to submit form
});
$(".js-add-ages").click(function (e) {
e.preventDefault();
$("form").validate({
rules: {
Age: {
required: true
}
},
messages: {
Age: "The Age is required"
}
});
if (!$("form").valid()) {
return;
}
// otherwise do stuff but we dont want to submit form
});
</script>
What I've noticed is that only one event handler works out the two based on whichever one was clicked first i.e. if I click the button with class js-add-names, the validation for that handler works as expected.
Now If I click the button with class js-add-ages having previously clicked js-add-names then the handler for js-add-age doesn't work and vis versa?
Any ideas why this is happening and what is the fix?
* UPDATE *
Further to suggestion by Sparky I have re-written the code as below but now when I click js-add-names, the validation for that handler works as expected
Now If I click the button with class js-add-ages having previously clicked js-add-names then the handler for js-add-age doesn't work becuase the validation has previously added a rule for input #Name. How do I reset the form or remove the rules each time the event handlers fire?
<form>
<input type="text" id="Name" name="Name">
<a class="btn btn-primary js-add-names" href="#">Add Names</a>
<input type="text" id="Age" name="Age">
<a class="btn btn-primary js-add-ages" href="#">Add Age</a>
// other inputs
<input type="checkbox" name="CarOwner" value="Yes"> Car owner
<input type="submit" value="Submit">
</form>
<script>
$("form").validate();
$(".js-add-names").click(function (e) {
e.preventDefault();
$("#Age").rules("remove");
$("#Name").rules("add", {
required: true,
messages: {
required: "The Name is required"
}
});
if (!$("form").valid()) {
return;
}
// otherwise do stuff but we dont want to submit form
// ...
//Reset input field
$("#Name").val('');
});
$(".js-add-ages").click(function (e) {
e.preventDefault();
$("#Name").rules("remove");
$("#Age").rules("add", {
required: true,
messages: {
required: "The Age is required"
}
});
if (!$("form").valid()) {
return;
}
// otherwise do stuff but we dont want to submit form
// ...
//Reset input field
$("#Age").val('');
});
</script>

Any ideas why this is happening and what is the fix?
The .validate() method is only used for initializing the plugin on your form and therefore should only be called once when the page is loaded. Subsequent calls are always ignored. So when you use one click handler, you initialize the validate plugin, and the other call to .validate() in the other click handler will do nothing.
The fix...
Call .validate() ONE time to initialize the plugin on your form.
Do NOT call .validate() from a click handler since this is not the testing method; it's only the initialization method.
Use the plugin's built-in submitHandler and invalidHandler functions for stuff you need to do when the form is valid and invalid.
Since you appear to be using your click handlers to add fields/rules to an existing form, then use the .rules('add') and .rules('remove') methods to add and remove any rules dynamically.

Related

JS - Collecting data from one function to run in another [duplicate]

There seems to be lots of info on how to submit a form using javascript, but I am looking for a solution to capture when a form has been submitted and intercept it in javascript.
HTML
<form>
<input type="text" name="in" value="some data" />
<button type="submit">Go</button>
</form>
When a user presses the submit button, I do not want the form to be submitted, but instead I would like a JavaScript function to be called.
function captureForm() {
// do some stuff with the values in the form
// stop form from being submitted
}
A quick hack would be to add an onclick function to the button but I do not like this solution... there are many ways to submit a form... e.g. pressing return while on an input, which this does not account for.
Ty
<form id="my-form">
<input type="text" name="in" value="some data" />
<button type="submit">Go</button>
</form>
In JS:
function processForm(e) {
if (e.preventDefault) e.preventDefault();
/* do what you want with the form */
// You must return false to prevent the default form behavior
return false;
}
var form = document.getElementById('my-form');
if (form.attachEvent) {
form.attachEvent("submit", processForm);
} else {
form.addEventListener("submit", processForm);
}
Edit: in my opinion, this approach is better than setting the onSubmit attribute on the form since it maintains separation of mark-up and functionality. But that's just my two cents.
Edit2: Updated my example to include preventDefault()
You cannot attach events before the elements you attach them to has loaded
It is recommended to use eventListeners - here one when the page loads and another when the form is submitted
This works since IE9:
Plain/Vanilla JS
// Should only be triggered on first page load
console.log('ho');
window.addEventListener("DOMContentLoaded", function() {
document.getElementById('my-form').addEventListener("submit", function(e) {
e.preventDefault(); // before the code
/* do what you want with the form */
// Should be triggered on form submit
console.log('hi');
})
});
<form id="my-form">
<input type="text" name="in" value="some data" />
<button type="submit">Go</button>
</form>
jQuery
// Should only be triggered on first page load
console.log('ho');
$(function() {
$('#my-form').on("submit", function(e) {
e.preventDefault(); // cancel the actual submit
/* do what you want with the form */
// Should be triggered on form submit
console.log('hi');
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<form id="my-form">
<input type="text" name="in" value="some data" />
<button type="submit">Go</button>
</form>
Not recommended but will work
If you do not need more than one event handler, you can use onload and onsubmit
// Should only be triggered on first page load
console.log('ho');
window.onload = function() {
document.getElementById('my-form').onsubmit = function() {
/* do what you want with the form */
// Should be triggered on form submit
console.log('hi');
// You must return false to prevent the default form behavior
return false;
}
}
<form id="my-form">
<input type="text" name="in" value="some data" />
<button type="submit">Go</button>
</form>
<form onSubmit="return captureForm()">
that should do. Make sure that your captureForm() method returns false.
Another option to handle all requests I used in my practice for cases when onload can't help is to handle javascript submit, html submit, ajax requests.
These code should be added in the top of body element to create listener before any form rendered and submitted.
In example I set hidden field to any form on page on its submission even if it happens before page load.
//Handles jquery, dojo, etc. ajax requests
(function (send) {
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
XMLHttpRequest.prototype.send = function (data) {
if (isNotEmptyString(token) && isNotEmptyString(header)) {
this.setRequestHeader(header, token);
}
send.call(this, data);
};
})(XMLHttpRequest.prototype.send);
//Handles javascript submit
(function (submit) {
HTMLFormElement.prototype.submit = function (data) {
var token = $("meta[name='_csrf']").attr("content");
var paramName = $("meta[name='_csrf_parameterName']").attr("content");
$('<input>').attr({
type: 'hidden',
name: paramName,
value: token
}).appendTo(this);
submit.call(this, data);
};
})(HTMLFormElement.prototype.submit);
//Handles html submit
document.body.addEventListener('submit', function (event) {
var token = $("meta[name='_csrf']").attr("content");
var paramName = $("meta[name='_csrf_parameterName']").attr("content");
$('<input>').attr({
type: 'hidden',
name: paramName,
value: token
}).appendTo(event.target);
}, false);
Use #Kristian Antonsen's answer, or you can use:
$('button').click(function() {
preventDefault();
captureForm();
});

Stopping submitting when alert is shown

I have form that has text input and submit. I'm trying to show an alert with Javascript if input is empty.
This is my code:
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, "");
}
function emptyArea() {
if (document.getElementById("type-text").value.trim() == '') {
alert("Please fill all fields");
} else("OK");
}
<form>
<input id="type-text" type="text" placeholder="Type some text">
<input type="submit" placeholder="Submit" onclick="emptyArea()">
</form>
When I click submit and it is empty, form still submits and doesn't show the alert. How would I prevent it from submitting and instead show an alert?
When I run your code, I actually do get alerts when I click "submit". Are you sure you are attaching the event handler correctly? I'm guessing maybe what's actually happening is that the alert is showing but then it submits anyway no matter if the form value is valid.
If you want to prevent the form from submitting, call e.preventDefault() where e is the event object which will be passed as the first argument to your handler function.
Here is an example codepen:
https://codepen.io/quinnfreedman/pen/PoqmGYb
function emptyArea(e) {
if (document.getElementById("text").value.trim() == '') { // .trim is supported by browsers since IE9
alert("Please fill all fields");
// the conditions were not met, so call preventDefault to
// stop the browsers default behavior of submitting the form
e.preventDefault();
e.stopPropagation();
} else {
// If we don't preventDefault, the form will submit after this alert
alert("OK")
}
}
document.getElementById("Submit").addEventListener("click", emptyArea)
<form action="#">
<input type="text" id="text" />
<input type="submit" id="Submit" />
<!-- NEVER call anything "submit" in a form -->
</form>

prevent validaton onfocusout depending of the radio button

I'm having problem to validate the form below.
The main issue is that I have to use the "onfocusout" function to validate the inputs.
The name input has be required depending of the radio selection.
When the "value3" is selected, the focus is set to the input.
While on the input, if the user tries to change the radio button, the onfocusout is triggered before the radio value is changed, and in that case the error is shown while it should not
Any suggestion?
<form id="myform">
<input type="radio" name="radio" value="value1" /> value1
<input type="radio" name="radio" value="value2" /> value2
<input type="radio" name="radio" value="value3" /> value3
<input type="text" name="name" />
<input type="submit" />
</form>
The js code is:
$("#myform").validate({
rules: {
name: {
required: {
depends: function () {
return $("input[name='radio']:checked").val() == "value3";
}
}
}
},
messages: {
name: {
required: "You must enter name"
}
},
onfocusout: function (element) {
this.element(element);
},
submitHandler: function (form) {
alert('success');
return false;
}
});
$("input[name='radio']").change(function () {
var value = $(this).val();
if (value == "value3") $("input[name='name']").focus();
else $("input[name='name']").valid();
});
JSFiddle: http://jsfiddle.net/954ros6L/
You are calling the .valid() method too late. Simply call it every time you change the radio buttons and the timing will be correct.
$("input[name='radio']").on('change', function () {
$("input[name='name']").valid(); // <- move it to here
var value = $(this).val();
if (value == "value3") {
$("input[name='name']").focus();
}
});
Plus, if you notice, the validation message now correctly appears when the field is invalid.
You also do not need a custom onfocusout handler.
DEMO: http://jsfiddle.net/954ros6L/4/
Sidenote:
You cannot use event.preventDefault() inside just any callback function since event is not a valid argument for the function. Besides, .preventDefault() is only meant to block the default action of an event, like stopping the page jump after an anchor click, etc. ... not the default behavior of a plugin.
To change the default behavior of onfocusout simply means that you write a function to override the plugin's default behavior, which you've already done.
Try using the following to prevent to normal event handlers
event.preventDefault();

Display only one error with jQuery Validation

I want to display one error message at the top, if validation fails. I don't want to use errorPlacement option. Instead I want to show the message in the Bootstrap alert.
Here is my HTML:
<form method="POST" action="/role" accept-charset="UTF-8" id="roles_form">
<div class="alert alert-danger vd_hidden">
<span class="vd_alert-icon"><i class="fa fa-exclamation-circle vd_red"></i></span>
Please select a role.
</div>
<input id="role_administrator" name="role" type="radio" value="administrator">
<label for="role_administrator">Administrator</label>
<input id="role_manager" name="role" type="radio" value="manager">
<label for="role_manager">Manager</label>
<input type="submit" value="Submit">
</form>
Here is my JavScript:
var roles_form = $('#roles_form');
var error_roles_form = $('.alert-danger', roles_form);
roles_form.validate({
focusInvalid: false, // do not focus the last invalid input
debug: true,
rules: {
role: "required"
},
invalidHandler: function (event, validator) { //display error alert on form submit
error_roles_form.fadeIn(500);
},
});
This does not work. Neither it does any validation (form gets submitted, if I remove the debug option) nor does it show any error.
Update:
After looking at the solution provided by Sparky, I realised that I am using a plugin to hide radio elements and replace with a style-able object. As the radio elements were hidden, jQuery Validation failed to validate them properly with my JavaScript code. What surprised me is that it did not show any JavaScript error, even with debug mode on.
Quote OP:
"This does not work. Neither does any validation (form gets submitted, if I remove the debug option) nor [does] it shows any error."
Actually, the code you posted is working: http://jsfiddle.net/TTJB7/
Quote OP:
"I want to display one error message at the top, if validation fails. I don't want to use errorPlacement option."
For placing the error message into a box, you'll need the errorLabelContainer option. So instead of the default behavior of putting error messages next to each input (errorPlacement), the errorLabelContainer will put the messages into one specified container that is hidden/shown automatically.
var roles_form = $('#roles_form');
var error_roles_form = $('.alert-danger', roles_form);
roles_form.validate({
focusInvalid: false, // do not focus the last invalid input
debug: true,
rules: {
role: "required"
},
messages: {
role: "Please select a role."
},
errorLabelContainer: error_roles_form // puts the error messages into this container
});
HTML:
<form id="roles_form">
<div class="alert alert-danger vd_hidden"></div>
<input id="role_administrator" name="role" type="radio" value="administrator" />
<input id="role_manager" name="role" type="radio" value="manager" />
<input type="submit" value="Submit" />
</form>
DEMO: http://jsfiddle.net/TTJB7/1/
For all other available callback options, see the documentation.
When I realised that the actual problem is with the hidden radio elements, I did a little research and solved the issue.
First I applied ignore to "" so that it will not ignore hidden elements and validate them.
Then I need to stop default error message to appear after the element. So I assigned an empty function to that option.
Here is my final JavaScript code:
roles_form.validate({
focusInvalid: false, // do not focus the last invalid input
ignore: "",
rules: {
role: "required"
},
invalidHandler: function (event, validator) { //display error alert on form submit
error_roles_form.fadeIn(500);
},
errorPlacement: function(error, element) {}
});

Intercept a form submit in JavaScript and prevent normal submission

There seems to be lots of info on how to submit a form using javascript, but I am looking for a solution to capture when a form has been submitted and intercept it in javascript.
HTML
<form>
<input type="text" name="in" value="some data" />
<button type="submit">Go</button>
</form>
When a user presses the submit button, I do not want the form to be submitted, but instead I would like a JavaScript function to be called.
function captureForm() {
// do some stuff with the values in the form
// stop form from being submitted
}
A quick hack would be to add an onclick function to the button but I do not like this solution... there are many ways to submit a form... e.g. pressing return while on an input, which this does not account for.
Ty
<form id="my-form">
<input type="text" name="in" value="some data" />
<button type="submit">Go</button>
</form>
In JS:
function processForm(e) {
if (e.preventDefault) e.preventDefault();
/* do what you want with the form */
// You must return false to prevent the default form behavior
return false;
}
var form = document.getElementById('my-form');
if (form.attachEvent) {
form.attachEvent("submit", processForm);
} else {
form.addEventListener("submit", processForm);
}
Edit: in my opinion, this approach is better than setting the onSubmit attribute on the form since it maintains separation of mark-up and functionality. But that's just my two cents.
Edit2: Updated my example to include preventDefault()
You cannot attach events before the elements you attach them to has loaded
It is recommended to use eventListeners - here one when the page loads and another when the form is submitted
This works since IE9:
Plain/Vanilla JS
// Should only be triggered on first page load
console.log('ho');
window.addEventListener("DOMContentLoaded", function() {
document.getElementById('my-form').addEventListener("submit", function(e) {
e.preventDefault(); // before the code
/* do what you want with the form */
// Should be triggered on form submit
console.log('hi');
})
});
<form id="my-form">
<input type="text" name="in" value="some data" />
<button type="submit">Go</button>
</form>
jQuery
// Should only be triggered on first page load
console.log('ho');
$(function() {
$('#my-form').on("submit", function(e) {
e.preventDefault(); // cancel the actual submit
/* do what you want with the form */
// Should be triggered on form submit
console.log('hi');
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<form id="my-form">
<input type="text" name="in" value="some data" />
<button type="submit">Go</button>
</form>
Not recommended but will work
If you do not need more than one event handler, you can use onload and onsubmit
// Should only be triggered on first page load
console.log('ho');
window.onload = function() {
document.getElementById('my-form').onsubmit = function() {
/* do what you want with the form */
// Should be triggered on form submit
console.log('hi');
// You must return false to prevent the default form behavior
return false;
}
}
<form id="my-form">
<input type="text" name="in" value="some data" />
<button type="submit">Go</button>
</form>
<form onSubmit="return captureForm()">
that should do. Make sure that your captureForm() method returns false.
Another option to handle all requests I used in my practice for cases when onload can't help is to handle javascript submit, html submit, ajax requests.
These code should be added in the top of body element to create listener before any form rendered and submitted.
In example I set hidden field to any form on page on its submission even if it happens before page load.
//Handles jquery, dojo, etc. ajax requests
(function (send) {
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
XMLHttpRequest.prototype.send = function (data) {
if (isNotEmptyString(token) && isNotEmptyString(header)) {
this.setRequestHeader(header, token);
}
send.call(this, data);
};
})(XMLHttpRequest.prototype.send);
//Handles javascript submit
(function (submit) {
HTMLFormElement.prototype.submit = function (data) {
var token = $("meta[name='_csrf']").attr("content");
var paramName = $("meta[name='_csrf_parameterName']").attr("content");
$('<input>').attr({
type: 'hidden',
name: paramName,
value: token
}).appendTo(this);
submit.call(this, data);
};
})(HTMLFormElement.prototype.submit);
//Handles html submit
document.body.addEventListener('submit', function (event) {
var token = $("meta[name='_csrf']").attr("content");
var paramName = $("meta[name='_csrf_parameterName']").attr("content");
$('<input>').attr({
type: 'hidden',
name: paramName,
value: token
}).appendTo(event.target);
}, false);
Use #Kristian Antonsen's answer, or you can use:
$('button').click(function() {
preventDefault();
captureForm();
});

Categories