I have reviewed several great Questions along the way, so many that I earned my badge for 40 votes in one day. But, nearly all Questions use a non-Vanilla dependency like jQuery or don't address my specific need. Here are two examples of wonderful, yet to-my-sorrow unrelated, Questions:
Ajax Form submit with preventDefault (jQuery)
preventDefault() on $.ajax complete (jQuery, and its pilgrimage of dup dups)
I'm surprised this Question has not been asked because I don't regard myself to be so imaginative. If this Question is already out there, I want to please open a Meta discussion on how to update that Question so searches can find it.
This is Vanilla JS, no dependencies.
The script uses preventDefault()
to interrupt a form
-submit
button identified by id
and call AJAX instead. AJAX works and changes content correctly. Then, the problem begins...
This AJAX responds with a replaced div
containing the same form
that preventDefault()
interrupts. But, AJAX doesn't recognize that updated form
-submit
button after the AJAX response JS-alters the div
containing that form
with the same id
.
<form id="same">
(success)<form id="same">
-> AJAX (success, first AJAX call)<form id="same">
(success, first AJAX response)<form id="same">
-> AJAX (broken, second AJAX call)Note, I need to process this specific form
. Other elements, including possible other forms, may be included in this div
that AJAX changes.
index.php:
(AJAX adapted from MDN - Sending forms through JavaScript: Using FormData bound to a form element)
<script>
window.addEventListener( "load", function () {
function sendData() {
const AJAX = new XMLHttpRequest(); // AJAX handler
const FD = new FormData( form ); // Bind to-send data to form element
AJAX.addEventListener( "load", function(event) {
document.getElementById("ajax_changes").innerHTML = event.target.responseText;
} ); // Change HTML on successful response
AJAX.addEventListener( "error", function( event ) {
document.getElementById("ajax_changes").innerHTML = 'Oops! Something went wrong.';
} );
AJAX.open( "POST", "ajax_responder.php" ); // Send data, ajax_responder.php can be any file or URL
AJAX.send( FD ); // Data sent is from the form
} // sendData() function
const form = document.getElementById( "ajaxForm" ); // Access <form id="ajaxForm">, id="ajaxForm" can be anything
form.addEventListener( "submit", function ( event ) { // Takeover <input type="submit">
event.preventDefault();
sendData();
} );
} );
</script>
<div id="ajax_changes">Replace me with AJAX<br>
<form id="ajaxForm">
<input type="text" value="AJAX" name="foo">
<input type="text" value="5" name="bar">
<input type="submit" value="Form AJAX!">
</form>
<!-- Possible other HTML elements and/or forms I do not want to process with that same AJAX -->
</div>
ajax_responder.php :
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$foo = $_POST['foo'];
$bar = $_POST['bar'];
echo '
'.$foo.'
<br>
'.$bar.'
<br>
<form id="ajaxForm">
<input type="text" value="'.$foo.'" name="foo">
<input type="text" value="'.$bar.'" name="bar">
<input type="submit" value="Form AJAX!">
</form>
<!-- Possible other HTML elements and/or forms -->
';
}
form
-submit
element?I have considered ways that do not respond with the same form
:
form
outside of the AJAX-changed contentBut both of those seem complicated.
There must be some way to tell AJAX to preventDefault()
on a form
-submit
button after that button has been updated by AJAX. I just don't know what that way is.
Or, is there another solution that still involves Vanilla JS?
You are binding the eventListener to the <form>
ajaxForm
. Then you replace it (= remove <form>
from DOM and add new <form>
to the DOM). In that case the eventListener is also removed.
To have an eventListener on the new form, you can either:
• Replace only the content of the <form>
. In that case the DOM element isn't removed and so the eventListener keeps intact
(don't forget to remove the <form>
tag in the php response). This is imho the easiest way.
document.getElementById("ajaxForm").innerHTML=
event.target.responseText;
• Bind a new eventListener everytime the <form>
is changed:
AJAX.addEventListener( "load", function(event) {
document.getElementById("ajax_changes").innerHTML =
event.target.responseText;
//=====> bind new eventListener here <======
} );
You can create a function that can be called on load as well in the ajax response
function addListenerToForm(){
document.getElementById( "ajaxForm" ).addEventListener( "submit", function ( event ) {
event.preventDefault();
sendData();
});
}
• bind the eventListener once to the container <div>
document.getElementById( "ajax_changes" ).addEventListener( "submit", function ( event ) {
event.preventDefault();
sendData();
});
function sendData(){
const AJAX = new XMLHttpRequest(); // AJAX handler
const form = document.getElementById( "ajaxForm");
const FD = new FormData( form );
...
}