I'm having trouble with stopping the propagation of a submit inside a form. It appears that no matter where I click within the webpage an event is fired - how can it be fixed to only fire upon clicking the submit button?
document.addEventListener('DOMContentLoaded', bindButtons);
function bindButtons() {
var buttons = document.getElementsByTagName('submit');
Array.prototype.forEach.call(buttons, addEventListener('click', function(event) {
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.addEventListener('load', function(event) {
// do stuff
})
event.preventDefault();
event.stopPropagation();
req.send(null);
}))
}
Submit is not a valid tag, you can find your submit buttons with the following code:
var submitButtons = document.getElementByTagNames('button').filter(button => button.getAttribute('type') === 'submit');
or, more verbose:
var submitButtons = document.getElementByTagNames('button').filter(function(button){
return (button.getAttribute('type') === 'submit')
);
Added each submit to the same class then stored those in an array using getElementsByClass() and iterated over that.
Related
I have two EventListeners, one to handle a form and the other for 'Add to Cart' buttons. When the events are fired, a post request is sent to the server which handles the according data, so i need the form to not be submitted but be handled by the server instead.
Before implementing the EventListeners which handles the 'Add to cart' buttons, the form was working as intended with the use of event.preventDefault();. With the buttons' EventListener however the form now submits and directs me to /login. I have tried every solution I found, I used .stopPropagation(), .preventDefault() and return=false; to both listeners, I changed the buttons to div elements. However the form is not working as intended unless I completely remove the second EventListener.
I would go on replacing the form element with a div but it needs to stay as an HTML form, so I have to work out a solution to this.
I'm including the code below, thanks in advance:
window.onload =function formSubmit(){
const form = document.getElementById('login-form');
form.addEventListener('submit', event => {
event.preventDefault(); // prevent the form from submitting
const username = form.elements.username.value;
const password = form.elements.password.value;
login(username, password);
});
}
//addbuttons are added dynamically after the other elements are already loaded so im putting a timeout for queryselector to gather them
setTimeout(window.onload =function productRequest(){
const purchaseBtns = document.querySelectorAll('.purchase-button');
purchaseBtns.forEach((btn) =>{
btn.addEventListener('click', () => {
var product_selected;
for(i in products){
if(products[i].id == btn.dataset.productId){
product_selected = products[i];
}
}
addToCart(product_selected);
});
});
}, 1000);
window.onload can store ONE function... No more.
Seems like the first one fires... And not the second because at that point, the load event already fired (before the second assignement overwrote the first, that is after the first timeout).
So try with one load event listener:
document.addEventListener("load", function(){
// Form's event listener
const form = document.getElementById('login-form');
form.addEventListener('submit', event => {
event.preventDefault(); // prevent the form from submitting
const username = form.elements.username.value;
const password = form.elements.password.value;
login(username, password);
});
// Buttons event listeners setting 1 second after page load
setTimeout(() => {
const purchaseBtns = document.querySelectorAll('.purchase-button');
purchaseBtns.forEach((btn) =>{
btn.addEventListener('click', (event) => {
// Prevent the event from bubbling to the form if the buttons are inside it
event.stopPropagation()
// and obviously, also prevent submit
event.preventDefault();
var product_selected;
for(i in products){ // Hoping you have that products defined...
if(products[i].id == btn.dataset.productId){
product_selected = products[i];
}
}
addToCart(product_selected);
});
});
}, 1000)
}) // end of the load event handler
I have a modal which contains check boxes to send delete request for the selected check boxes and I have issue of multiple requests in case of dismissing once and submitting the next time
/* Delete Url dialog */
var $deleteEntriesDialog = null;
this.$editor.on("show.bs.modal", "#delete-url-modal", (e) => {
$deleteEntriesDialog = $(e.currentTarget);
$deleteEntriesDialog.find(".modal-body").html("");
var text = $el.parent().parent().data("raw").text;
var modalBody = this.machinery.renderDeleteUrls(text);
$deleteEntriesDialog.find(".modal-body").append(modalBody);
});
The DELETE request is fired multiple times (it seems that each dismiss adds one repetition).
Here's what I am doing on submition:
this.$editor.on("submit", ".delete-url-form", (e) => {
var $form = $(e.currentTarget);
var $deleteEntries = $form.find("input.form-check-input:checked");
$deleteEntriesDialog.modal("hide");
Object.entries($deleteEntries).forEach(([_, entry]) => {
if (typeof entry.id !== "undefined") {
this.removeTranslationEntry(entry.id); // Delete AJAX request function
}
});
return false;
});
I believe here is the issue - the events are bind when the dialog is shown, so in case it is shown multiple times (dismissing it between), the submit handler is also triggered multiple times causing duplicate DELETE requests.
I have tried to resolve the issue by doing this:
this.$editor.on("hide.bs.modal", "#delete-url-modal", () => {
$deleteEntriesDialog = null;
});
This is not helping in case if submit happens after one dismiss, the $deleteEntriesDialog is null so gives a TypeError.
I've two button on submit form.
1. Add to Cart Button
2. Buy Now Button
I need to add disable class if the button was clicked,
submitForm: function (form) {
var addToCartButton, buyNowButton, self = this;
if (form.has('input[type="file"]').length && form.find('input[type="file"]').val() !== '') {
self.element.off('submit');
// disable 'Add to Cart' button
addToCartButton = $(form).find(this.options.addToCartButtonSelector);
buyNowButton = $(form).find(this.options.buyNowButtonSelector);
if(addToCartButton){
addToCartButton.prop('disabled', true);
addToCartButton.addClass(this.options.addToCartButtonDisabledClass);
}else if(buyNowButton){
buyNowButton.prop('disabled', true);
buyNowButton.addClass(this.options.buyNowButtonDisabledClass);
}
form.submit();
} else {
self.ajaxSubmit(form);
}
},
Try it like this (JQuery):
$(".classNameOfButton").click(function(){functionName(this)});
Pure Javascript, here you go :)
document.addEventListener('DOMContentLoaded', () => {
const button = document.querySelector("button");
button.addEventListener("click", (e) => {
e.target.disabled = true
})
});
wait for DOM content to get loaded (probably not necessary in your case as it will be part of larger codebase
get button element you need
addEventListener for click to that element
set disabled to true
About event.target
https://developer.mozilla.org/pl/docs/Web/API/Event/target
Codepen:
https://codepen.io/pen/
JS:
// Disable default Event (Browser reloading..)
const formElement = document.getElementByID("formID");
formElement.addEventListener("submit", () => {
event.preventDefault();
});
const button1 = document.getElementByID("button1");
button1.addEventListener("click", (event) => {
// do something...
e.target.classList.add("disabled");
});
const button2 = document.getElementByID("button2");
button2.addEventListener("click", (event) => {
// do something...
e.target.classList.add("disabled");
});
Prevent Default Action of a form submit button (reload site)
get both buttons and attach an "click" event listener
If clicked add "disabled" class
I have a WordPress site and there is Contact form 7 plugin and I want to add attr to submit button to disable double submission.
Now I have this code to prevent double submission
$(document).on('click', '.wpcf7-submit', function(e){
if( $('.ajax-loader').hasClass('is-active') ) {
e.preventDefault();
return false;
}
});
but I want to add attr disabled while form sending or getting error response for better user experience
Improving on Matt's answer -
$('.wpcf7-form').on('submit', function() {
$(this).find('.wpcf7-submit').attr('disabled', true);
});
This would disable the submit button when clicked on it. Now to get that activated again after success or failure you would need to remove the attribute after the submission is complete(whether success or failure). Since the plugin developer is a bit whimsical about how the events work, I am writing this solution for first quarter of 2019 -
$('.wpcf7').on('wpcf7submit', function (e) {
$(this).find('.wpcf7-submit').removeAttr('disabled');
});
where '.wpcf7' is the parent container of the form, '.wpcf7-form' is the form itself. The 'wpcf7submit' is event listener that the DOM listens to, after the form gets submitted(irrespective of the fact that is valid or invalid).
This will disable the button and submit the form. You need to re-call submit after disabling the button.
jQuery( '.wpcf7-submit' ).click(function() {
jQuery( this ).attr( 'disabled', true );
jQuery( this ).submit();
});
This will re-enable the button if there's an error with the submission.
document.addEventListener( 'wpcf7invalid', function() {
jQuery( '.wpcf7-submit' ).attr( 'disabled', false );
}, false );
$(document).on('click', '.wpcf7-submit', function(e){
$(this).prop('disabled',true);
});
I implemented this script to help prevent multiple submissions. The biggest difference from the others is that it works with multiple CF7 forms on each page. Basically, it disables the form and the submit button on submit (since a form can also be submitted with an Enter-press), adds a new label "Please Wait.." to the submit button, and re-enables them if there are input errors. Also, not dependent on jQuery (Vanilla JS).
(function () {
var elems = document.querySelectorAll('.wpcf7');
if (!elems.length) {
return false;
}
var forms = document.querySelectorAll('.wpcf7-form');
if (!forms.length) {
return false;
}
function _evtFormSubmit() {
this.disabled = true;
var submitBtn = this.querySelector('button[type="submit"]');
submitBtn.disabled = true;
submitBtn.setAttribute('data-default-text', submitBtn.innerText);
submitBtn.innerHTML = '<span>Please wait...</span>';
}
function _evtInvalid(e) {
var thisForm = document.querySelector('#' + e.detail.id + ' form');
thisForm.disabled = false;
var submitBtn = thisForm.querySelector('button[type="submit"]');
setTimeout(function() {
submitBtn.disabled = false;
submitBtn.innerHTML = '<span>' + submitBtn.getAttribute('data-default-text') + '</span>';
}, 600); // give it a bit of time in case it is a fast submit
}
for(var i = forms.length-1; i >= 0; i--) {
forms[i].addEventListener('submit', _evtFormSubmit, false);
}
for(i = elems.length-1; i >= 0; i--) {
elems[i].addEventListener('wpcf7invalid', _evtInvalid, false);
}
})();
Note: if you have more than one submit button (why?), this only affects the first button in the form.
For future people who are looking for a solution here. Simple SCSS/CSS option without Javascript need. For me is work pefect. It always works reliably for me. (2022)
.wpcf7-form {
&.submitting {
.wpcf7-submit {
pointer-events: none;
}
}
}
I have a form that is split into sections. When the user clicks "continue", I have a jquery script that checks to see if all required fields are filled out. If any aren't, then a box appears with a warning and buttons (They are actually <a> tags) for 'yes' and 'no'. I attach an onclick event to the 'yes' button that triggers a function. The function works, but a # appears in the address bar (website.com/page#), which I'm guessing is because the event.preventDefault(); in my code isn't working.
Here is the function that adds the onclick event:
function checkSection (event, check, goTo) {
event.preventDefault();
var emptyFields = "0";
$("#ia"+check+"Div .check").each(function() {
var val = $(this).val();
if (val == "") {
emptyFields++;
}
});
if (emptyFields >= 1) {
$(".mask").show();
$("#warningBox").show();
$(document).on("click", "#yesBtn", function() {
var x = window['save'+check];
x(event, goTo);
$("#warningBox").hide();
$(".mask").hide();
});
} else {
var x = window['save'+check];
x(event, goTo);
$("#warningBox").hide();
}
}
Here is the tag I am adding the event to:
<div class="medBtn short">
<div class="btnTbl">
Yes
</div>
</div>
The function I end up calling is like this:
function saveContact(event, val) {
event.preventDefault();
//Do Stuff - This is the function where event.preventDefault(); isn't working
}
Like I said, the function still works, so if it's not something I can get around, that is fine. I just don't like having a # in the address bar.
The event object doesn't exist until the event occurs
You prevent default inside the actual event handler
$(document).on("click", "#yesBtn", function(event) {
event.preventDefault();
....
})