Reputation: 429
I need an answer to what I'm doing wrong in the below js. I have a bs5 form that the submission is not being prevented if fields are left blank or invalid. The html/css validation does work correctly when fields are invalid but submission is still allowed.
I am not well-versed at writing javascript (as you can tell) so any help is much appreciated!
(function () {
"use strict";
// Fetch all the forms we want to apply custom Bootstrap validation styles to
let forms = document.querySelectorAll(".needs-validation");
// Loop over them and prevent submission
Array.from(forms).forEach(function (form) {
form.addEventListener("submit", function (event) {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add("was-validated");
}, false
);
});
forms.forEach( function(e) {
e.addEventListener('submit', function(event) {
event.preventDefault();
let thisForm = this;
let action = thisForm.getAttribute('action');
let recaptcha = thisForm.getAttribute('data-recaptcha-site-key');
if( ! action ) {
displayError(thisForm, 'The form action property is not set!')
return;
}
thisForm.querySelector('.loading').classList.add('d-block');
thisForm.querySelector('.error-message').classList.remove('d-block');
thisForm.querySelector('.sent-message').classList.remove('d-block');
let formData = new FormData( thisForm );
if ( recaptcha ) {
if(typeof grecaptcha !== "undefined" ) {
grecaptcha.ready(function() {
try {
grecaptcha.execute(recaptcha, {action: 'php_email_form_submit'})
.then(token => {
formData.set('recaptcha-response', token);
php_email_form_submit(thisForm, action, formData);
})
} catch(error) {
displayError(thisForm, error)
}
});
} else {
displayError(thisForm, 'The reCaptcha javascript API url is not loaded!')
}
} else {
php_email_form_submit(thisForm, action, formData);
}
});
});
function php_email_form_submit(thisForm, action, formData) {
fetch(action, {
method: 'POST',
body: formData,
headers: {'X-Requested-With': 'XMLHttpRequest'}
})
.then(response => {
if( response.ok ) {
return response.json()
} else {
throw new Error(`${response.status} ${response.statusText} ${response.url}`);
}
})
.then(data => {
thisForm.querySelector('.loading').classList.remove('d-block');
if (data.type === 'success') {
thisForm.querySelector('.sent-message').classList.add('d-block');
thisForm.reset();
} else {
throw new Error(data ? data : 'Form submission failed and no error message returned from: ' + action);
}
})
.catch((error) => {
displayError(thisForm, error);
});
}
function displayError(thisForm, error) {
thisForm.querySelector('.loading').classList.remove('d-block');
thisForm.querySelector('.error-message').innerHTML = error;
thisForm.querySelector('.error-message').classList.add('d-block');
}
})();
Upvotes: 0
Views: 1391
Reputation: 150
In order for your event.stopPropagation()
command in the first declaration to happen, you must pass true
instead of false
to the useCapture
argument of your addEventListener
function.
Otherwise both will fire concurrently and none will take precedence over the other, and the only behaviour stopPropagation
will achieve is stop the bubbling from the submit event, which won't help in what you're trying to achieve.
Edit: As stated in throught the comments, an alternative solution would be having both the validation and execution of the code happen under the same listener.
// code before ...
forms.forEach(function(e) {
e.addEventListener('submit', function(event) {
event.preventDefault();
if (!e.checkValidity()) {
e.removeClass("was-validated");
return; // interrupts the code to happen due to being invalid
}
e.addClass("was-validated");
//...rest of the code
})
});
// code after ...
Related note: event.stopImmediatePropagation()
might be necessary in order to achieve the same behaviour in the browser Firefox
Upvotes: 1