22

Current Setup

I have an HTML form like so.

<form id="demo-form" action="post-handler.php" method="POST">
   <input type="text" name="name" value="previousValue"/>
   <button type="submit" name="action" value="dosomething">Update</button>
</form>

I may have many of these forms on a page.

My Question

How do I submit this form asynchronously and not get redirected or refresh the page? I know how to use XMLHttpRequest. The issue I have is retrieving the data from the HTML in javascript to then put into a post request string. Here is the method I'm currently using for my zXMLHttpRequest`'s.

function getHttpRequest() {
    var xmlhttp;
    if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp=new XMLHttpRequest();
    } else {// code for IE6, IE5
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    
    return xmlhttp;
}

function demoRequest() {
       var request = getHttpRequest();
       request.onreadystatechange=function() {
             if (request.readyState == 4 && request.status == 200) {
                   console.log("Response Received");
             }
       }
       request.open("POST","post-handler.php",true);
       request.setRequestHeader("Content-type","application/x-www-form-urlencoded");
       request.send("action=dosomething");
}

So for example, say the javascript method demoRequest() was called when the form's submit button was clicked, how do I access the form's values from this method to then add it to the XMLHttpRequest?

EDIT

Trying to implement a solution from an answer below I have modified my form like so.

<form id="demo-form">
       <input type="text" name="name" value="previousValue"/>
       <button type="submit" name="action" value="dosomething" onClick="demoRequest()">Update</button>
</form>

However, on clicking the button, it's still trying to redirect me (to where I'm unsure) and my method isn't called?

Button Event Listener

document.getElementById('updateBtn').addEventListener('click', function (evt) {
                                evt.preventDefault();
                                
                                // Do something
                                updateProperties();
                                
                                return false;
                            });
StuStirling
  • 14,067
  • 20
  • 82
  • 138
  • You tagged jQuery but there is no jQuery code... Do you want to use jQuery or pure javascript ? – Brewal Sep 03 '13 at 12:47
  • Sorry misclick. Just javascript – StuStirling Sep 03 '13 at 12:49
  • I posted an answer that you can use via jquery though – Roy M J Sep 03 '13 at 12:50
  • 1
    possible duplicate of [Sending POST data with a XMLHttpRequest](http://stackoverflow.com/questions/9713058/sending-post-data-with-a-xmlhttprequest) – oHo Nov 05 '13 at 13:34
  • To prevent the default form action, set an event listener on the _form's submit event_, instead of the button's click event. (And still call `evt.preventDefault();`) – Mashmagar Mar 16 '20 at 14:25
  • In your edit captioned "Button Event Listener", where exactly would you put that code? into the functions demoRequest() body? why the return false statement? – Tanque Jul 30 '20 at 06:30

6 Answers6

30

The POST string format is the following:

name=value&name2=value2&name3=value3


So you have to grab all names, their values and put them into that format. You can either iterate all input elements or get specific ones by calling document.getElementById().

Warning: You have to use encodeURIComponent() for all names and especially for the values so that possible & contained in the strings do not break the format.

Example:

var input = document.getElementById("my-input-id");
var inputData = encodeURIComponent(input.value);

request.send("action=dosomething&" + input.name + "=" + inputData);

Another far simpler option would be to use FormData objects. Such an object can hold name and value pairs.

Luckily, we can construct a FormData object from an existing form and we can send it it directly to XMLHttpRequest's method send():

var formData = new FormData( document.getElementById("my-form-id") );
xhr.send(formData);
ComFreek
  • 27,416
  • 16
  • 97
  • 150
  • Do I override the button's `onClick` function and point it to my `XMLHttpRequest` method? – StuStirling Sep 03 '13 at 12:56
  • @DiscoS2 Yes. Do you have any other event handlers registered for the click event? – ComFreek Sep 03 '13 at 12:57
  • Not for this form no. – StuStirling Sep 03 '13 at 12:58
  • Thank you for expanding on your answer more. I am having issues submitting the form. I have remove the action and method from the `
    ` tag as it was still posting via `HTML`. How do I call my `javascript` method?
    – StuStirling Sep 03 '13 at 13:05
  • @DiscoS2 How did you assign the event listener? Can you show us the code (in your answer - not in a comment, please)? – ComFreek Sep 03 '13 at 13:08
  • Added the code in my original question. However, its not a listener... unsure of how to do this? – StuStirling Sep 03 '13 at 13:18
  • @DiscoS2 Try this code: http://jsfiddle.net/ZsHgu/ (add an ID to your button and register an event listener as provided in the fiddle). – ComFreek Sep 03 '13 at 13:28
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/36728/discussion-between-disco-s2-and-comfreek) – StuStirling Sep 03 '13 at 13:41
  • Your code does not work with file uploads... I used `var formData = new FormData( document.getElementById("my-form-id") );` and `formData` is empty. – Black Apr 25 '18 at 10:43
  • @Black According to [MDN on FormData objects](https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects), it should work. Did you use a POST or GET request? – ComFreek Apr 25 '18 at 12:20
  • @ComFreek, It works now. It was not working because of a wrong header (https://stackoverflow.com/questions/50020648/upload-file-to-server-asynchronously-via-form-and-xmlhttprequest) – Black Apr 25 '18 at 12:39
  • This doesn't work in an addon. how to do this without overriding the onsubmit()? addons/extensions do not allow overriding onsubmit due to security reasons. – john ktejik Jul 03 '18 at 01:27
19

The ComFreek's answer is correct but a complete example is missing.

Therefore I have wrote an extremely simplified working snippet:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge, chrome=1"/>

<script>
"use strict";
function submitForm(oFormElement)
{
  var xhr = new XMLHttpRequest();
  xhr.onload = function(){ alert(xhr.responseText); }
  xhr.open(oFormElement.method, oFormElement.getAttribute("action"));
  xhr.send(new FormData(oFormElement));
  return false;
}
</script>
</head>

<body>
<form method="POST"
      action="post-handler.php"
      onsubmit="return submitForm(this);" >
   <input type="text"   value="previousValue" name="name"/>
   <input type="submit" value="Update"/>
</form>
</body>
</html>

This snippet is basic and cannot use GET. I have been inspired from the excellent Mozilla Documentation. Have a deeper read of this MDN documentation to do more. See also this answer using formAction.

oHo
  • 41,098
  • 25
  • 141
  • 183
  • When I use this method my form is submitting multiple(2) times. Any suggestion? – Mayur Patel Sep 26 '17 at 06:56
  • 2
    Today I just found a small fix for this. I have changed `onsubmit="submitForm(this);"` to `onsubmit="return submitForm(this);"`. Rest of your code remains same. This solved my problem. Thanks. – Mayur Patel Sep 28 '17 at 06:11
  • 1
    Thank you @MayurPatel very much for your feedback. I have just edited the snippet to reflect your contribution. Have fun ;-) – oHo Sep 29 '17 at 09:10
  • You should use `oFormElement.getAttribute("action")` in case you ever add an input field named "action", which will override your `oFormElement.action`. Same goes for method ofc – h3n Aug 09 '19 at 09:12
  • Thank you @h3n for your advice I have just applied your trick. Should I do the same for `oFormElement.getAttribute("method")`? I am a bit afraid my original tiny snippet is becoming more complex... What do you think? Have fun – oHo Aug 27 '19 at 22:50
  • @olibre Async is by default true, so you don't need it - https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open#Parameters –  Sep 25 '19 at 14:29
3

By the way I have used the following code to submit form in ajax request.

 $('form[id=demo-form]').submit(function (event) {

    if (request) {
        request.abort();
    }
    // setup some local variables
    var $form = $(this);

    // let's select and cache all the fields
    var $inputs = $form.find("input, select, button, textarea");


    // serialize the data in the form
    var serializedData = $form.serialize();


    // fire off the request to specific url

    var request = $.ajax({
        url : "URL TO POST FORM",
        type: "post",
        data: serializedData
    });
    // callback handler that will be called on success
    request.done(function (response, textStatus, jqXHR){


    });

    // callback handler that will be called on failure
    request.fail(function (jqXHR, textStatus, errorThrown){

    });

    // callback handler that will be called regardless
    // if the request failed or succeeded
    request.always(function () {
        // reenable the inputs

    });

    // prevent default posting of form
    event.preventDefault();
});
Awais Qarni
  • 14,876
  • 22
  • 72
  • 134
0

With pure Javascript, you just want something like:

var val = document.getElementById("inputFieldID").value;

You want to compose a data object that has key-value pairs, kind of like

name=John&lastName=Smith&age=3

Then send it with request.send("name=John&lastName=Smith&age=3");

Zlatko
  • 16,414
  • 12
  • 60
  • 116
0

I have had this problem too, I think.

I have a input element with a button. The onclick method of the button uses XMLHTTPRequest to POST a request to the server, all coded in the JavaScript.

When I wrapped the input and the button in a form the form's action property was used. The button was not type=submit which form my reading of HTML standard (https://html.spec.whatwg.org/#attributes-for-form-submission) it should be.

But I solved it by overriding the form.onsubmit method like so:

form.onsubmit = function(E){return false;}

I was using FireFox developer edition and chromium 38.0.2125.111 Ubuntu 14.04 (290379) (64-bit).

JasonMArcher
  • 12,386
  • 20
  • 54
  • 51
Worik
  • 139
  • 1
  • 5
-1
function postt(){
    var http = new XMLHttpRequest();
    var y = document.getElementById("user").value;
    var z = document.getElementById("pass").value;
    var postdata= "username=y&password=z"; //Probably need the escape method for values here, like you did

    http.open("POST", "chat.php", true);

    //Send the proper header information along with the request
    http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    http.setRequestHeader("Content-length", postdata.length);

    http.onreadystatechange = function() {//Call a function when the state changes.
        if(http.readyState == 4 && http.status == 200) {
            alert(http.responseText);
        }
    }
    http.send(postdata);
}

how can I post the values of y and z here from the form

BWA
  • 5,314
  • 7
  • 29
  • 42
  • If you have a separate question, you should create one rather than posting an answer on an already existing question. Thank you. – the_new_mr Apr 19 '21 at 07:53