jQuery: Form Submission - Multiple Event Handlers - javascript

Currently having some issues with jQuery Form Submissions in my project.
My project contains a general jQuery Code which prevents form double submissions (e.g. someone clicks the 'submit' button multiple times).
//prevent multiple form submissions
jQuery.fn.preventDoubleSubmission = function () {
$(document).on('submit', this, function (e) {
let $form = $(this);
if ($form.data('submitted') === true) {
e.preventDefault();
} else {
$form.data('submitted', true);
}
});
return this;
};
$(function () {
$('form').preventDoubleSubmission();
});
This code is included into every single page - so every form should be 'protected'.
For some specific forms I need to check some values before they are submitted - and show a confirm box, if some values are missing (e.g. Are you sure you want to submit this form without value X?)
Here's the code:
$(document).on('submit', 'form[name="article"]', function (e) {
e.preventDefault();
let form = this;
let $form = $(form);
let $category = $form.find('select#article_category'); //get category
if ($category.length && !$category.val()) { //check if category is selected
$.confirm({ //jquery confirm plugin
title: "Are you sure?",
content: "Value X is missing - continue?",
buttons: {
confirm: {
action: function () {
$form.off('submit');
form.submit();
}
}
}
});
} else {
$form.off('submit');
form.submit();
}
});
So basically, if the user tries to submit the form, but the value X is missing, there will be a Yes/No Popup first - if the value exists, the form will be submitted right away.
Problem:
When I want to submit the form, I call $form.off('submit'); to remove the event handler and submit afterwards with form.submit();. Sadly this also removes my preventDoubleSubmission event handler, which allows double submissions again.
Is there a way to fix my issue? Thanks

Below is a code snippet with a correct solution. There were multiple issues with your original approach, highlighted below the snippet. Better to run this snippet in a different code playground, where action with javascript work, e.g. JSFiddle.
//prevent multiple form submissions
function submitOnce (e, $form) {
alert('submitted = ' + $form.data('submitted'));
if ($form.data('submitted') === true) {
e.preventDefault();
alert('Double-submission prevented!');
} else {
$form.data('submitted', true);
alert('Double-submission param saved');
}
}
$(document).on('submit', 'form[name="article"]', function (e) {
let form = this;
let $form = $(form);
let $category = $form.find('select#article_category'); //get category
if ($category.length && !$category.val()) { //check if category is selected
if ( confirm("Are you sure?") ){
submitOnce(e,$form);
}
else {
e.preventDefault();
}
} else {
submitOnce(e,$form);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form name="article" action="javascript:alert('Form submitted!');">
<select id="article_category" name="select1">
<option></option>
<option>option1</option>
<option>option2</option>
</select>
<input type="submit" />
</form>
edit: adding explanations
$form.off() would work if you would bind 'submit' event handler directly on the form element, but in both cases handlers are registered on the document.
Calling form.submit() is not necessary, since we are already in a submit handler, hence submit already called. We just need to prevent submissions to continue.
Better is to have just one submit handler, and deal with double submits there.
e.preventDefault(); has to be just in the else clause for a non-confirmed case and in submitOnce(). You had it at the beginning of the main handler, but it was useless there, since form.submit() was called again inside, and this call does not prevent the default.
My approach is not bullet-proof and serves just as a demonstration of what needed to be changed.

One approach is to use a normal span with a click event. Once it is clicked you can disable it (using a class for example) and then submit form. This approach allows you to control form submission without the need of extra coding.
See this example:
$submitBtn = jQuery(".submit");
$form = jQuery("form[name='article']");
$submitBtn.on("click", function() {
if (jQuery(this).hasClass("disabled"))
return;
let $category = $form.find('.name'); //get value
if ($category.length && !$category.val()) { //check if value is set
$.confirm({ //jquery confirm plugin
title: "Are you sure ?",
content: 'Value x is missing - continue ?',
buttons: {
confirm: {
action: function() {
$form.submit();
$submitBtn.addClass("disabled");
}
},
cancel: function() {
//$.alert('canceled');
}
}
});
return;
}
$submitBtn.addClass("disabled");
$form.submit();
});
form {
border: 1px solid rgba(0, 0, 0, 0.1);
padding: 1.5rem;
display: flex;
flex-direction: column;
width: 200px;
}
form input {
margin-bottom: 0.5rem;
padding: 0.3rem;
border-radius: 3px;
border: 1px solid gray;
}
form .submit {
padding: 0.3rem 1rem;
cursor: pointer;
border-radius: 3px;
background-color: rgba(0, 0, 0, 0.1);
text-align: center;
transition: all 0.3s;
}
form .submit.disabled {
opacity: 0.5;
cursor: default;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.2/jquery-confirm.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.4/jquery-confirm.min.js"></script>
<form action="" name='article'>
First name:<br>
<input type="text" name="firstname" value="My First Name" class='name'>
<br> Last name:<br>
<input type="text" name="lastname" value="My Last Name">
<br><br>
<span class='submit'>Submit</span>
</form>

So I finally figured out a relatively ok solution for me. However it is very simple and I might stick with it.
//form submission function
function submitForm(form) {
let $form = $(form);
let $submit = $form.find('button[type=submit]'); //find submit button
$submit.attr('disabled', true); //disable button = prevent double submission
form.submit(); //submit form
}
//submission for every form but not .form-confirm
$(document).on('submit', 'form:not(.form-confirm)', function (e) {
e.preventDefault();
submitForm(this); //call function
});
$(document).on('submit', 'form[name="article"]', function (e) {
e.preventDefault();
let form = this;
let $form = $(form);
let $category = $form.find('select#article_category'); //get category
if ($category.length && !$category.val()) { //check if category is selected
$.confirm({
title: "Are you sure?",
content: "Value X is missing - continue?",
buttons: {
confirm: {
action: function () {
submitForm(form); //call function
}
}
}
});
} else {
submitForm(form); //call function
}
});
So how does it work?
Basically I just disable the submit button after submitting (=prevent double submissions). I added a class called form-confirm to the specific form which the popup should show, so the general rule does not work there.
I always use preventDefault and use form.submit() to submit right away in my code.

Related

Disable button until certain condition is met

I'm trying to make website which will enable button when the certain condition is met. But when I run it within simple if the condiiton is checked only at the beginning and it doesn't enable and disable on changing condition. Condition is changing inside other event listener so the condition is dynamically. The condition is met when the dicitonary consists only of true which means that input is proper
`var submitButton = document.getElementById("submit_button");`
And after some event listeners connected to inputs
`if(Object.values(check_dict).filter(x=>x==true).length === 6)
{
submitButton.disabled = false;
}
else
{
submitButton.disabled = true ;
}`
pretty straight forward. add an eventlistener to the input you want to watch and then disable the submit button inside the function
document.getElementById('test').addEventListener('input',myFunc)
function myFunc(){
if(event.target.value == "x")document.getElementById("submit_button").disabled = true;
else document.getElementById("submit_button").disabled = false;
}
<input id ='submit_button' type='submit'>
<input id='test'>
You could use removeAttribute() and setAttribute() to toggle the state of the submit button using a conditional.
See the snippit for a very simple example of how to toggle states using classes with .classList along with add/remove attribute method.
const checkInput = (e) => {
if(e.target.value.length >= args.rules.length){
e.target.classList.remove('error')
e.target.classList.add('success')
submitBtn.removeAttribute('disabled')
inputDisplay.textContent = args.success.value
}else{
e.target.classList.add('error')
e.target.classList.remove('success')
submitBtn.setAttribute('disabled', 'true')
inputDisplay.textContent = args.error.value
}
}
const args = {
rules: {
length: 8
},
success: {
value: "Success! You may submit now!"
},
error: {
value: "Input must contain 8 or more characters!"
}
}
const fname = document.getElementById('fname')
const submitBtn = document.getElementById('submit')
const inputDisplay = document.getElementById('input-display')
inputDisplay.textContent = args.error.value
submitBtn.disabled = 'true'
fname.addEventListener('input', checkInput)
.success {
color: darkgreen;
background-color: lightgreen;
}
.error {
color: darkred;
background-color: pink;
}
<input name="firstname" id="fname" placeholder="Please enter your first name">
<button id="submit" type="button">Submit</button>
<div id="input-display"></div>

HTML make h-captcha mandetory in a form [duplicate]

I'm using Google reCAPTCHA and have been able to add the CAPTCHA component to my page inside a form. But when I submit the form there's no validation taking place to check if the CAPTCHA has been solved.
How do I validate that the CAPTCHA component has been solved when submitting my form? Or, in other words, how do I make my CAPTCHA component required?
if you want to use the native html5 popups, than here is the solution
JavaScript:
window.addEventListener('load', () => {
const $recaptcha = document.querySelector('#g-recaptcha-response');
if ($recaptcha) {
$recaptcha.setAttribute('required', 'required');
}
})
CSS:
#g-recaptcha-response {
display: block !important;
position: absolute;
margin: -78px 0 0 0 !important;
width: 302px !important;
height: 76px !important;
z-index: -999999;
opacity: 0;
}
I had the same problem as yours and solved it this way:
First declare a variable that stores 1 or 0 depending or whether the user filled the capcha correctly.
var allowSubmit = false;
Then you need a function which gets executed when the user fills the reCapcha correctly:
function capcha_filled () {
allowSubmit = true;
}
... and a function that gets executed when the reCapcha session expires:
function capcha_expired () {
allowSubmit = false;
}
To tell reCapcha about your functions (callbacks), set those data-attributes in your html:
<div class="g-recaptcha"
data-callback="capcha_filled"
data-expired-callback="capcha_expired"
data-sitekey="your site key"></div>
Or if you use explicit load:
var onloadCallback = function() {
grecaptcha.render('your_div_id', {
'sitekey' : 'your_site_key',
'callback': capcha_filled,
'expired-callback': capcha_expired,
});
};
You need also a callback for the form submission:
function check_if_capcha_is_filled (e) {
if(allowSubmit) return true;
e.preventDefault();
alert('Fill in the capcha!');
}
Finally add in the form the onsubmit attribute:
<form action="..." onsubmit="check_if_capcha_is_filled">
Note: as mentioned in the comments, a server validation is still needed. The code prevents accidentally submitting the form unless the capcha is filled and is only for user's convenience.
I found this to be a quick & easy way to do it. Add this to your headers:
<script>
window.onload = function() {
var recaptcha = document.forms["myForm"]["g-recaptcha-response"];
recaptcha.required = true;
recaptcha.oninvalid = function(e) {
// do something
alert("Please complete the captcha");
}
}
</script>
This only works in HTML5, and is (or should be) supported by these browsers: http://caniuse.com/#feat=form-validation
(The JS console in Chrome shows this error message: "Invalid form control" only in Google Chrome , and I haven't been able to work around this. Hopefully someone else will improve this response.)
I checked for existance of #g-recaptcha-response:
function checkRecaptcha() {
res = $('#g-recaptcha-response').val();
if (res == "" || res == undefined || res.length == 0)
return false;
else
return true;
}
//...
$('#frm-signup').submit(function(e) {
if(!checkRecaptcha()) {
$( "#frm-result" ).text("Please validate your reCAPTCHA.");
return false;
}
//...
});
This really should be part of the docs...
Working solution in 2022
Personally, I was not able to get any of the above solutions to work with my captcha. So I figured I would share my current working solution for those facing the same issue.
The accepted answer doesn't have a validation technique for when the captcha expires, the below solution addresses that.
My notes in the .js should explain the solution thoroughly.
JavaScript
// By default do not allow form submission.
var allow_submit = false
function captcha_filled () {
/*
* This is called when Google get's the recaptcha response and approves it.
* Setting allow_submit = true will let the form POST as normal.
* */
allow_submit = true
}
function captcha_expired () {
/*
* This is called when Google determines too much time has passed and expires the approval.
* Setting allow_submit = false will prevent the form from being submitted.
* */
allow_submit = false
}
function check_captcha_filled (e) {
console.log('captcha-verified')
/*
* This will be called when the form is submitted.
* If Google determines the captcha is OK, it will have
* called captcha_filled which sets allow_submit = true
* If the captcha has not been filled out, allow_submit
* will still be false.
* We check allow_submit and prevent the form from being submitted
* if the value of allow_submit is false.
* */
// If captcha_filled has not been called, allow_submit will be false.
// In this case, we want to prevent the form from being submitted.
if (!allow_submit) {
// This call prevents the form submission.
// e.preventDefault()
// This alert is temporary - you should replace it with whatever you want
// to do if the captcha has not been filled out.
alert('ERROR: Please verify you are human by filling out the captcha')
return false
}
captcha_expired()
return true
}
HTML
<form action="post" onsubmit="return check_captcha_filled()">
<!-- form items -->
<div class="g-recaptcha"
data-callback="captcha_filled"
data-expired-callback="captcha_expired"
data-sitekey="your site key">
</div>
</form>
Not sure if you already solved this, but you could use an addon to validate the Google recaptcha:
http://formvalidation.io/addons/recaptcha2/
If you want a more friendly and descriptive message, you can add a required checkbox.
This will ensure the html5 popup shows something like: "Please check this box if you want to proceed"
<div class="captcha">
<div class="g-recaptcha" data-sitekey="Your Site Key" data-callback="removeFakeCaptcha"></div>
<input type="checkbox" class="captcha-fake-field" tabindex="-1" required>
</div>
Add the code to remove the fake captcha once completed
window.removeFakeCaptcha = function() {
document.querySelector('.captcha-fake-field').remove();
}
Then on the css you hide the checkbox and position it to the captcha box:
.captcha {
position: relative;
}
.captcha-fake-field {
background: transparent;
bottom: 0;
border: none;
display: block;
height: 1px;
left: 12px;
width: 1px;
position: absolute;
z-index: -1;
}
I find this very helpful:
<div class="g-recaptcha myPopover" data-sitekey="Your Key"
data-callback="recaptchaCallback">
You add a function to data-callback="recaptchaCallback" with this code:
var recaptchachecked=false;
function recaptchaCallback() {
recaptchachecked = true;
}
and a function were you return the value to use it in a other html-tag like this:
<form method="post" onsubmit="return isreCaptchaChecked()">
function isreCaptchaChecked()
{
return recaptchachecked;
}
I hope this helps you.
Once the captcha expires this doesn't make it mandatory and it proceeds with button click and further validations.
Any other way to re-validate and force user to verify captcha? I am using Captcha V2 with checkbox.

Change dynamically number of rows on submit

I need your help guys.
I use a textarea that automatically expands by changing the number of rows.
In my project, the page does not reload and stays as it is after submitting the form. I need to change dynamically the number of rows (2) on submit.
Also one can send the form by Enter. So I need to change the number of rows after pushing a button or hitting the Enter key.
I've coded a rough sketch of the form that I have in my project so that you could test it: https://codepen.io/C3La-NS/pen/NagZbr
<form id="NewMessage">
<textarea id="shoutbox-comment" data-min-rows="2"></textarea>
<button id="send_message" type="submit" onclick="chatSubmit();">send</button>
</form>
JS:
// auto-resizing textarea
const textarea = document.getElementById("shoutbox-comment");
textarea.addEventListener("input", function() {
this.rows = 2; // Erm...
this.rows = countRows(this.scrollHeight);
});
function countRows(scrollHeight) {
return Math.floor(scrollHeight / 20); // 20px = line-height: 1.25rem
}
// submit by Enter
$(document).ready(function() {
$("#shoutbox-comment").on("keypress", function(event) {
if (event.keyCode == 10 || event.keyCode == 13) {
event.preventDefault();
chatSubmit();
}
});
});
// submit FORM
function chatSubmit() {
$("#NewMessage").submit();
}
Thank you!
jQuery submit accept as parameter a callback that is triggered before submit so, you can do:
$("#NewMessage").submit(function( event ) {
event.preventDefault();
$('#shoutbox-comment').attr('rows', 2);
});
Just couple of changes in your script:
const textarea = $("#shoutbox-comment");
const minRows = textarea.data('minRows');
textarea.on("input", function(e) {
this.rows = 1; // Erm...
this.rows = countRows(this.scrollHeight);
});
function countRows(scrollHeight) {
var toReturn = Math.floor(scrollHeight / 20); // 20px = line-height: 1.25rem
return toReturn > minRows ? toReturn : minRows;
}
// submit by Enter
$(document).ready(function() {
$("#shoutbox-comment").on("input", function(e) {
if (e.keyCode == 10 || e.keyCode == 13) {
e.preventDefault();
chatSubmit();
}
});
});
// submit FORM
function chatSubmit() {
// Send the message via AJAX;
textarea.val('').trigger('input');
return false;
}
#shoutbox-comment {
width: 220px;
outline: none;
resize: none;
line-height: 20px;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="NewMessage">
<textarea id="shoutbox-comment" data-min-rows="2"></textarea>
<button id="send_message" type="submit" onclick="chatSubmit();">send</button>
</form>
I've also included data-min-rows attribute inside the script.
Also on CodePen.

enable submit button after validation the form in jquery validation plugin [duplicate]

I have an enabled and disabled state for the submit button on my form.
The conditions are as follows:
If all input fields have been entered and are valid enable the submit button.
If some fields have not been entered do not enable the submit button.
So far the validation is being done within the onkeyup event and is only working for the first input:
//Custom onkeyup validation
onkeyup: function(element) {
//Check if input is empty remove valid class from parent
var formInput = $(element),
formInputParent = $(element).parent('fieldset');
if(formInputParent.hasClass('form--valid') && formInput.val() === "") {
formInputParent.removeClass('form--valid');
}
//Check if all fields are not empty to remove submit--disabled class
var formInputs = $('form').find(':input');
console.log(formInputs);
formInputs.each(function(){
if(formInputs.length > 0) {
formInputs.parents('form').find('.submit-form').removeClass('submit--disabled');
}
});
}
Check here for a DEMO
You would simply construct a blur (or even a keyup) handler function to toggle the button based on the form's validity. Use the plugin's .valid() method to test the form.
$('input').on('blur', function() {
if ($("#myform").valid()) {
$('#submit').prop('disabled', false);
} else {
$('#submit').prop('disabled', 'disabled');
}
});
DEMO: http://jsfiddle.net/sd88wucL/
Instead, you could also use both events to trigger the same handler function...
$('input').on('blur keyup', function() {
if ($("#myform").valid()) {
$('#submit').prop('disabled', false);
} else {
$('#submit').prop('disabled', 'disabled');
}
});
DEMO 2: http://jsfiddle.net/sd88wucL/1/
Source: https://stackoverflow.com/a/21956309/594235
The code below is what I ended up with so far:
$('#formId').on('blur keyup change', 'input', function(event) {
validateForm('#formId');
});
function validateForm(id) {
var valid = $(id).validate().checkForm();
if (valid) {
$('.form-save').prop('disabled', false);
$('.form-save').removeClass('isDisabled');
} else {
$('.form-save').prop('disabled', 'disabled');
$('.form-save').addClass('isDisabled');
}
}
// Run once, so subsequent input will be show error message upon validation
validateForm('#formId');
It uses checkForm() instead of the form() and my disable button has the classform-save
It is based on #Sparky's answer
There is an issue filed on the jquery-validation git repo.
$('form').find(':input').each(function(index, value){
//action for every element
$(value);
});
In this case you can do this that way: (but I dont like this solution)
var areSomeFieldsEmpty = false;
$('form').find(':input').each(function(i, v){
if ($(v).val().length <= 0){
areSomeFieldsEmpty = true;
}
});
if (!areSomeFieldsEmpty){
//unlock form
}
http://jsfiddle.net/89y26/335/
<html>
<form id="form">
name<br>
<input type="text"><br>
Roll Number<br>
<input type="number"><br>
<input id="next" type="submit" disabled="disabled">
</form>
</html>
Initially, I have set submit button disabled and for each change in the input tag I will call a function to validate the form using jquery
$("input[type='text'], input[type='number']").on("input", function () {
validate();
});
function validate(){
var show = true;
$("input[type='text'], input[type='number']").each(function(){
if($(this).val()==''){
show = false;
}
});
if(show){
$('#next').css({cursor:'pointer'})
$('#next').removeAttr('disabled')
}
else {
$('#next').css({cursor:'not-allowed'})
}
}
});

How do I keep a NAME when I disable a button with Javascript?

I have code similar to this:
<INPUT TYPE="submit" NAME="VAR1" VALUE="X" OnClick="
this.disabled=true;
this.value='Submitting...';
this.form.submit();">
The problem is that I need that name in the handler but it seems that disabling the button also disables the name. I tried adding 'this.name="VAR1";' but that didn't work. Does anyone know how to pass the information that a specific button was pressed? It doesn't have to be a name. Alternative methods welcome.
Here's an example that you can do. Just prevent default event on keypress. This will allow you to access the attributes. You can also do some styling to it by accessing it's data ref.
(function(){
// Attach DOM
var debug = document.getElementById('debug');
var elm = document.querySelectorAll('[data-disabled="false"]');
for (var i = 0; i < elm.length; i++) {
elm[i].addEventListener('click', function(evt) {
// Disable default event
evt.preventDefault();
// Disabled State
evt.target.dataset.disabled = true;
evt.target.value = 'Submitting...';
// Log Information to DOM
debug.innerHTML = this.getAttribute('name') + ' is still accessible, but input is disabled by disabling click so that the user doesn\nt submit anything, but the attributes can still be read.';
// Artificial request, completes in 2 seconds
setTimeout(function() {
evt.target.value = 'Done!';
evt.target.dataset.disabled = false;
}, 2000);
});
}
})();
input {
border: 1px solid black;
padding: 5px;
}
input[data-disabled="true"]{
background: red;
}
<input type="submit" name="superInput" data-disabled="false" value="Submit" />
<div id="debug"></div>

Categories