Html form, how to send data by traditional post and jquery ajax to various servers at the same time

I want to save html form data in my server and to an another server. For this data is sending by traditional post (refreshing the page) to local server and also by jquery ajax post (or javascript) to the remote server. The html form:

<!DOCTYPE HTML>
<html>
<head>
<style>
.error {color: #FF0000;}
</style>
</head>
<body>
<script type="text/javascript" src='jquery.js'></script>
<script type="text/javascript" src='e.js'></script>
<h2>PHP Form Validation Example</h2>
<p><span class="error">* required field</span></p>
<form method="post" id="registration" action="receiver1.php">
Name: <input type="text" id="nameq" name="name" value="">
<span class="error">* </span>
<br><br>
E-mail: <input type="text" id="email" name="email" value="">
<span class="error">* </span>
<br><br>
Website: <input type="text" id="website" name="website" value="">
<br><br>
Comment: <textarea id="comment" name="comment" rows="5" cols="40"></textarea>
<br><br>
Gender:
<input type="radio" id="gender" name="gender" value="female">Female
<input type="radio" id="gender" name="gender" value="male">Male
<input type="radio" id="gender" name="gender" value="other">Other
<span class="error">* </span>
<br><br>
<table width='100%'>
<tr>
<td align='center'>
<input type='image' src='image/submit_button.jpg'>
</td>
</tr>
</table>
</form>
</html>

here action=“receiver1.php” is file in my server http://localhost/receiver1.php. I make handler on input type=‘image’, e.js:

$(document).ready(function() {
$("table tr input:image").click(function() {
var cln = $("#nameq").val();
$.post("https://remote-server/receiver2.php", {"cln": cln});
});
});

https://remote-server/receiver2.php is file in an another server. But it does not work, I can’t receive data in remote server. Have someone a perfect solution for this problem? Thanks in advance

1 Like

you need to prevent the default action (which is reloading the page - there is a js function for that: event.preventDefault within the handler), Then send to the second server and then run the real submission.

Also. Never attach click handlers to a form to listen for submission. There is an extra submit handler there.
But in the moment you click on the submit button (the image) the event “submit” already triggers reloading the page.

I’m writing an example

1 Like

Have a look at the headers in the network panel of the browser dev tools to see what exactly went wrong… but most likely it’s getting blocked because the remote server doesn’t allow CORS.

However I would suggest to only send it to “your” server in the first place, and then forward it to the other server from there if necessary. This way CORS won’t be a issue, and you’ll also reduce the user bandwidth usage.

Edit: x-post… yes the race condition with the actual form submission may be a problem too, although the request should at least get sent.

1 Like

Alternatively - why not have your server send a copy to the other server?
Has the following benefits:

  1. No CSP/CORS involved
  2. No eventhandler needed
  3. Can’t be blocked by user
2 Likes

I managed to do it client-side:

The event that triggers the submission (and thus reloads the page) ignores all other events that come after the default event (page reload).

What you need is a state to check whether or not you have already handled the submission:

// your state
let submitted = false
document.querySelector('form').addEventListener('submit', async event => {
    // if already submitted, don't run again
	if (submitted) return
    // prevents reloading the page to do other stuff
	event.preventDefault()
    // send the data
	const body = JSON.stringify(trasnformFormDataToJSON(new FormData(event.target)))
	await fetch('', { body, method: 'POST'} )
    // set our state to true and run submit again.
	submitted = true
	event.target.submit()
})
1 Like

Thank you all for the answers.

  1. It is not CSP/CORS because there is header(“Access-Control-Allow-Origin: *”); in php
  2. “Also. Never attach click handlers to a form to listen for submission” so what should I use instead of that?

Right now I have two solutions: Solution #1 by using ajax complete() method:

$(document).ready(function() {
  $("table tr input:image").click(function() {
	$.ajax({
	  type: "POST",
	  url: 'https://remote-server/receiver2.php',
	  data: {cln: $("#nameq").val()},
	  complete: function(){ //ajax complete() method
		  $("form").submit(); //submit the form after ajax completes
	  }
	});
	return false; //stop the form from initially submitting
  });
});

and Solution #2, using by ajax async:

$(document).ready(function() {
	$("table tr input:image").click(function() {
		var cln = $("#nameq").val();
		$.ajaxSetup({async: false}); //set ajax async to false
		$.post("https://remote-server/receiver2.php", {"cln": cln});
	});
});

so my question is which solution would be better to use? In case of performance, speed, efficient etc? What are the negative and positive sides of each of these methods, or both are the same?

Never use synchronous AJAX requests (the first “A” actually stands for “asynchronous”) as this blocks the entire script execution until the response is received; and if you’re going to use AJAX for both requests that’s not even necessary as you can just send both simultaneously:

$.when(
  $.post("https://remote-server/receiver1.php", {"cln": cln}),
  $.post("https://remote-server/receiver2.php", {"cln": cln})
).done(function (response1, response2) {
  console.log('all done', response1, response2)
})

Still though, if you’re not interested in both responses I would only send one request to the server and have your backend handle the other one.

1 Like

I would like to solve this problem as it is by changing only e.js. The form is unchangeable, so method="post" id="registration" action="receiver1.php" is always exist, so data will saved in local server. My goal is get this data and try to save them to the remote server by changing only javascript and without interfering with traditional post (refreshing the page). How about your example, I can’t send both requests simultaneously like in your code:

$.when(
  $.post("https://remote-server/receiver1.php", {"cln": cln}),
  $.post("https://remote-server/receiver2.php", {"cln": cln})
).done(function (response1, response2) {
  console.log('all done', response1, response2)
})

since reciever1.php already in <form method="post" id="registration" action="receiver1.php">. Am I right?

No, you can send both but if you do you’ll have to prevent the default form submission…

$('#registration').on('submit', function (event) {
  event.preventDefault()
  
  $.when(
    // Send the complete form data to the action URL like
    // in a regular form submission
    $.post(this.action, $(this).serialize()),
    // Send the desired data to the other server
    $.post('https://remote-server/receiver2.php', { 'cln': 'foo' })
  ).done(function (response1, response2) {
    console.log('all done', response1, response2)
  })
})

If you send the complete form data to the server (as shown above) then this wouldn’t make any difference to a regular form submission for the backend; however the client would be responsible to display a success message or something.

If you must use a regular form submission then you might indeed submit() the form programmatically once the other AJAX requests completes, but this would cause an expected delay for the user and probably make your site feel slow. You should at least show a loading spinner or the like then until the form gets actually submitted.

1 Like

“No, you can send both but if you do you’ll have to prevent the default form submission… If you send the complete form data to the server (as shown above) then this wouldn’t make any difference to a regular form submission for the backend; however the client would be responsible to display a success message or something.”
Works like a charm, but is there a solution without event.preventDefault()? Because I must redirect to receiver1.php

" If you must use a regular form submission then you might indeed submit() the form programmatically once the other AJAX requests completes, but this would cause an expected delay for the user and probably make your site feel slow. You should at least show a loading spinner or the like then until the form gets actually submitted."
Yea it is a problem - delay and make site feel slow. Ideally I would not want this, also show a loading banner etc.

so given all this, is there another improved solution?

  1. As already explained in my posts: use the submit event. This way, your handler will also be fired in the case of your user completing the form by pressing ENTER in one of the text input fields. There are more ways than sending a form than a click.
  2. Forms are a game of faking… Either you are happy with the default capabilities of a form or you have to re-produce all the capabilities all on your own, INCLUDING the default behavior. Not including the default behavior (e.g. not reacting on the submit event) will cause your users headache.

I wrote a blogpost about this topic: https://happy-css.com/articles/html-form-semantics-are-a-lie/

1 Like

I got it about submit event thanks. But I am still looking for perfect solution of this problem. Cause all of these solutions above can’t overcome it ideally. In the code who offer m3g4p0p there is no redirect to receiver1.php which mandatory for me. The second solution by ajax induces delay of server

What’s wrong with my solution?

// your state
let submitted = false
document.querySelector('form').addEventListener('submit', async event => {
    // if already submitted, don't run again
	if (submitted) return
    // prevents reloading the page to do other stuff
	event.preventDefault()
    // send the data
	const body = JSON.stringify(Object.fromEntries(new FormData(event.target).entries()))
	await fetch('', { body, method: 'POST'} )
    // set our state to true and run submit again.
	submitted = true
	event.target.submit()
})
1 Like

Well then you either have to wait for the AJAX request to complete before submitting the form, or don’t intercept the form submission at all and send the other request from the server. I don’t see any other possibilities here.

What is the purpose of the redirect though? As a workaround, you might push redirect.php to the browser history so that it appears as if there had been a redirect. And if you just want to display the markup that redirect.php responds with, you might render that using JS inside the done() callback.

1 Like

Actually, there is another option… if you’re using fetch() instead of jQuery’s $.post() like @MartinMuzatko suggested, you can just set flag to keep the request alive after leaving the page. This way you don’t even have to prevent the default event:

$('#registration').on('submit', function () {
  fetch('https://remote-server/receiver2.php', {
    method: 'POST',
    body: new FormData(this),
    keepalive: true
  }).catch(console.error)
})
1 Like

Sorry for the late response. Now I have 3 beautiful solutions:

Solution #1. Ajax complete() method

$(document).ready(function() {
  $("table tr input:image").click(function() {
	$.ajax({
	  type: "POST",
	  url: 'https://remote-server/receiver2.php',
	  data: {cln: $("#nameq").val()},
	  complete: function(){ //ajax complete() method
		  $("form").submit(); //submit the form after ajax completes
	  }
	});
	return false; //stop the form from initially submitting
  });
});

disadvantages of the method - delay of the server

Solution #2. event.preventDefault()

$('#registration').on('submit', function (event) {
  event.preventDefault()
  
  $.when(
    // Send the complete form data to the action URL like
    // in a regular form submission
    $.post(this.action, $(this).serialize()),
    // Send the desired data to the other server
    $.post('https://remote-server/receiver2.php', { 'cln': 'foo' })
  ).done(function (response1, response2) {
    console.log('all done', response1, response2)
  })
})

disadvantages of the method - no redirect to receiver1.php

Solution #3. fetch

// your state
let submitted = false
document.querySelector('form').addEventListener('submit', async event => {
    // if already submitted, don't run again
	if (submitted) return
    // prevents reloading the page to do other stuff
	event.preventDefault()
    // send the data
	const body = JSON.stringify(Object.fromEntries(new FormData(event.target).entries()))
	await fetch('', { body, method: 'POST'} )
    // set our state to true and run submit again.
	submitted = true
	event.target.submit()
})

disadvantages of the method - 1. All versions of internet explorer does not support this api. 2. In my html form when user does not fill the field, there will be no redirect to receiver1.php, but the code is interfering with this logic and allow redirect even if the field is empty. 3. If I use m3g4p0p raw fetch code without any state, there is error, in mozilla firefox - TypeError: NetworkError when attempting to fetch resource

Hm true… it does work using navigator.sendBeacon() though:

$('#registration').on('submit', function () {
  navigator.sendBeacon(
    'https://remote-server/receiver2.php', 
    new FormData(this)
  )
})

Mind you, neither that nor fetch() available in IE so you’d have to include a polyfill here or, indeed, use jQuery – but either way you probably won’t be able to replicate the keepalive behaviour.

BTW the gist of solution #3 is the same as in solution #1, it just uses an API and language features unknown to IE.

1 Like

Thanks you all for these solutions)

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.