582

I'd like to send some data using an XMLHttpRequest in JavaScript.

Say I have the following form in HTML:

<form name="inputform" action="somewhere" method="post">
  <input type="hidden" value="person" name="user">
  <input type="hidden" value="password" name="pwd">
  <input type="hidden" value="place" name="organization">
  <input type="hidden" value="key" name="requiredkey">
</form>

How can I write the equivalent using an XMLHttpRequest in JavaScript?

Kamil Kiełczewski
  • 53,729
  • 20
  • 259
  • 241
Jack Greenhill
  • 8,952
  • 11
  • 37
  • 67

13 Answers13

826

The code below demonstrates on how to do this.

var http = new XMLHttpRequest();
var url = 'get_data.php';
var params = 'orem=ipsum&name=binny';
http.open('POST', url, true);

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

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

In case you have/create an object you can turn it into params using the following code, i.e:

var params = new Object();
params.myparam1 = myval1;
params.myparam2 = myval2;

// Turn the data object into an array of URL-encoded key/value pairs.
let urlEncodedData = "", urlEncodedDataPairs = [], name;
for( name in params ) {
 urlEncodedDataPairs.push(encodeURIComponent(name)+'='+encodeURIComponent(params[name]));
}
rkachach
  • 13,862
  • 5
  • 35
  • 55
Ed Heal
  • 55,822
  • 16
  • 77
  • 115
  • 49
    Is it possible to send an object in `params` instead of a string like in jQuery? – Vadorequest Sep 07 '14 at 11:27
  • 1
    Correct me if I'm wrong, but doesn't jquery just encode the object into a series of key-value pairs? You could always base64-encode the object although this may lead to unwieldy urls – Dan Apr 16 '15 at 13:08
  • @DanPantry - The question is not tagged jquery – Ed Heal Apr 16 '15 at 14:26
  • 4
    No, but @Vadorequest's comment mentioned jQuery - he asked if it were possible to pass data "like jQuery". I mentioned how I think jQuery does it and thus, how you could achieve this. – Dan Apr 16 '15 at 14:33
  • 11
    @EdHeal, `Connection` and `Content-Length` headers cannot be set. It'll say "Refused to set unsafe header "content-length"" . See http://stackoverflow.com/a/2624167/632951 – Pacerier Jun 27 '15 at 10:55
  • 84
    Note: setRequestHeader() **after** open(). Took me an hour, let's hope this comment saves someone an hour ;) – Kevin Sep 26 '16 at 08:30
  • 5
    is it possible to send an `application/json` request? –  Dec 06 '16 at 03:03
  • 2
    You should be able to set any custom content type, as long as your server knows how to interpret it. – Bernard Feb 03 '17 at 07:21
  • 1
    it's also noteworthy to mention the third param in `setRequestHeader` which expects a bool which determines if the request is cached or not...this could cause a serious headache if the result is cached as further requests would fail – Matthew Brent Aug 02 '17 at 20:39
  • I just tested and my Express API accepted application/json like a hot damn. The code in this above answer works if you paste it in and change the encoding type. Then, you can make `params` an object. Just make sure your API handles it. I am using bodyParser with JSON enabled. – agm1984 Sep 08 '17 at 08:52
  • 2
    And.... you need to `JSON.stringify()` the params or it will throw invalid JSON error in the Backend. – agm1984 Sep 08 '17 at 09:01
  • 2
    `true` argument in `http.open` method specifies synchronicity per [w3school link](https://www.w3schools.com/xml/dom_httprequest.asp). It'd better to write code like `const async = true; http.open(..., async);` – transang Dec 15 '17 at 12:55
  • 3
    `application/x-www-form-urlencoded` tells the server to expect that the data submitted is url encoded. The values in the answer ("ipsum" and "binny") don't include any characters that require encoding, but if they did that can be accomplished using encodeURIComponent('value'). For example `encodeURIComponent('this&that')` would return `this%26that`. Otherwise the server would interpret the `&` as delimiting the next key=value pair. – frederickf Jan 03 '18 at 21:00
  • You can use https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams to ease the management of query params. – ufukomer Aug 01 '18 at 17:34
  • is it possible if using this post request and then we got the response of *.xls format or something being downloaded? – gumuruh Sep 25 '19 at 14:02
  • If you are receiving an empty array to your server, despite having used the code above, recall whether you are hiding the file extensions in your server configuration. If you are, then making the request to (e.g.) "get_data.php" will be redirected to "get_data", and thus your POST array is lost. In that example, dropping the extension does the trick. – Fom Oct 08 '19 at 19:10
  • Is there anywhere to find the request headers that are appropriate to use online? I'm having some issues with the "GET" command and would like to try "POST", but I don't know what the appropriate headers are for my file type. – Zibbobz Aug 05 '20 at 15:14
292
var xhr = new XMLHttpRequest();
xhr.open('POST', 'somewhere', true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onload = function () {
    // do something to response
    console.log(this.responseText);
};
xhr.send('user=person&pwd=password&organization=place&requiredkey=key');

Or if you can count on browser support you could use FormData:

var data = new FormData();
data.append('user', 'person');
data.append('pwd', 'password');
data.append('organization', 'place');
data.append('requiredkey', 'key');

var xhr = new XMLHttpRequest();
xhr.open('POST', 'somewhere', true);
xhr.onload = function () {
    // do something to response
    console.log(this.responseText);
};
xhr.send(data);
uKolka
  • 27,488
  • 4
  • 29
  • 43
  • 6
    FormData takes the form element as its constructor argument, no need to add values indivually – Juan Mendes Jun 22 '13 at 05:51
  • 6
    Yes, but question was to write JavaScript equivalent of provided form not submit the form using JavaScript. – uKolka Jun 22 '13 at 17:07
  • 3
    The answer that has few votes but got marked correct uses two extra headers: `http.setRequestHeader("Content-length", params.length);` and `http.setRequestHeader("Connection", "close");`. Are they needed? Are they perhaps only needed on certain browsers? (There is a comment on that other page saying setting the Content-Length header was "exactly what was needed") – Darren Cook Oct 17 '13 at 00:19
  • @Darren Cook Implementation dependent. From my experience major browsers set ['Content-length'](http://tinyurl.com/ymjn3w) (it is required) [automatically](http://tinyurl.com/mhsbzzz) from the data you supply. ['Connection'](http://tinyurl.com/mz8k7px) header defaults to 'keep-alive' in most cases, which keeps connection open for a while so subsequent requests don't have to reestablish connection again as in case of 'close'. You can try those snippets in the console, using current page URL and inspect request headers using browser's tools or [wireshark](http://www.wireshark.org/). – uKolka Oct 18 '13 at 00:46
  • I am using `data = new FormData()` and `xhr.send(data);`, but my method in the controller is never fired. What method parameters should I be using in the controller, I currently have `[HttpPost] public async Task Upload(HttpContext context){ ... }`. This is clearly not right, but what should I use? – MoonKnight Dec 23 '14 at 11:00
  • @Killercam I think your comment should be a question. Doesn't seem like it has anything to do with XHR. – uKolka Dec 29 '14 at 19:26
  • 4
    @uKolka it should be noted on the reply than with your second solution the request `Content-Type` changes automatically to `multipart/form-data`. This has serious implications on the server side and how the information is accessed there. – AxeEffect Jul 10 '17 at 09:29
117

Use modern JavaScript!

I'd suggest looking into fetch. It is the ES5 equivalent and uses Promises. It is much more readable and easily customizable.

const url = "http://example.com";
fetch(url, {
    method : "POST",
    body: new FormData(document.getElementById("inputform")),
    // -- or --
    // body : JSON.stringify({
        // user : document.getElementById('user').value,
        // ...
    // })
}).then(
    response => response.text() // .json(), etc.
    // same as function(response) {return response.text();}
).then(
    html => console.log(html)
);

In Node.js, you'll need to import fetch using:

const fetch = require("node-fetch");

If you want to use it synchronously (doesn't work in top scope):

const json = await fetch(url, optionalOptions)
  .then(response => response.json()) // .text(), etc.
  .catch((e) => {});

More Info:

Mozilla Documentation

Can I Use (96% Nov 2020)

David Walsh Tutorial

Gibolt
  • 24,018
  • 9
  • 129
  • 89
  • 6
    You should avoid using Promises and fat arrows for things this critical to webpage functionality, as many devices do not have browsers that support these features. – Dmitry Sep 02 '17 at 13:30
  • 10
    [Promises](https://caniuse.com/#feat=promises) are 90% covered. I added `function()` examples in case you don't prefer [`=>`](https://caniuse.com/#feat=arrow-functions). You should absolutely be using modern JS to ease the developer experience. Worrying about a small percentage of people stuck on IE isn't worth it unless you are a huge enterprise – Gibolt Sep 02 '17 at 20:06
  • 5
    Fat arrow also doesn't work with `this` keyword. I like to mention that, but I also secretly hate people that use `this`, and inheritance architecture instead of function factories. Forgive me, I am node. – agm1984 Sep 08 '17 at 09:17
  • 3
    I avoid `this` like the plague as well, and so should anyone reading `this`. – Gibolt Oct 20 '17 at 17:28
  • 3
    If worried about compatibility...Google es6 transpiler... https://stackoverflow.com/questions/40205547/using-babel-to-transpile-to-es3-safari-compliant. Write it simple. Deploy it compatible. +1 avoid `this`. – TamusJRoyce Dec 27 '17 at 17:25
  • 1
    Is there a way to specify Content-Type using the `fetch()` function? – Madeyedexter Dec 28 '17 at 13:14
  • There are plenty of good reasons to use `this`. I like to mention that. Also, use Babel for transpiling. – Adam the Impaler Aug 07 '18 at 16:28
  • 2
    What? Avoid `this` because I **can't** understand it? Kappa. – mrReiha Jul 09 '19 at 15:20
  • 2
    The synchronous example is wrong, it shouldn't use `then` after `await`, you immediately have access to the contents in the variable. If you feel inclined to check, you need a `try-catch` block. – Eddie's Feb 27 '20 at 07:05
41

Here is a complete solution with application-json:

// Input values will be grabbed by ID
<input id="loginEmail" type="text" name="email" placeholder="Email">
<input id="loginPassword" type="password" name="password" placeholder="Password">

// return stops normal action and runs login()
<button onclick="return login()">Submit</button>

<script>
    function login() {
        // Form fields, see IDs above
        const params = {
            email: document.querySelector('#loginEmail').value,
            password: document.querySelector('#loginPassword').value
        }

        const http = new XMLHttpRequest()
        http.open('POST', '/login')
        http.setRequestHeader('Content-type', 'application/json')
        http.send(JSON.stringify(params)) // Make sure to stringify
        http.onload = function() {
            // Do whatever with response
            alert(http.responseText)
        }
    }
</script>

Ensure that your Backend API can parse JSON.

For example, in Express JS:

import bodyParser from 'body-parser'
app.use(bodyParser.json())
Dharman
  • 21,838
  • 18
  • 57
  • 107
agm1984
  • 9,418
  • 3
  • 51
  • 69
  • 1
    Great, but don't use 'false' value for the async parameter in XMLHttpRequest.open - it's deprecated and will give a warning – johnnycardy Mar 23 '18 at 15:29
  • Should we put true there or just omit that parameter? I will update the answer if you can specify which is preferable. – agm1984 Apr 16 '18 at 19:56
  • 1
    It should default to true but I don't know if all browsers respect that – johnnycardy Apr 17 '18 at 08:58
  • Given the default of true, I am going to remove it from the example and drop this URL for research: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open – agm1984 Apr 17 '18 at 19:09
  • 1
    I like that better because it's reasonable and one less detail for someone to start with. Thanks for highlighting it. – agm1984 Apr 17 '18 at 19:11
  • `// Make sure to stringify` is super important! This answer needs upvoting. – Paul Kruger Apr 26 '19 at 07:28
40

Minimal use of FormData to submit an AJAX request

<!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); } // success case
  xhr.onerror = function(){ alert (xhr.responseText); } // failure case
  xhr.open (oFormElement.method, oFormElement.action, true);
  xhr.send (new FormData (oFormElement));
  return false;
}
</script>
</head>

<body>
<form method="post" action="somewhere" onsubmit="return submitForm(this);">
  <input type="hidden" value="person"   name="user" />
  <input type="hidden" value="password" name="pwd" />
  <input type="hidden" value="place"    name="organization" />
  <input type="hidden" value="key"      name="requiredkey" />
  <input type="submit" value="post request"/>
</form>
</body>
</html>

Remarks

  1. This does not fully answer the OP question because it requires the user to click in order to submit the request. But this may be useful to people searching for this kind of simple solution.

  2. This example is very simple and does not support the GET method. If you are interesting by more sophisticated examples, please have a look at the excellent MDN documentation. See also similar answer about XMLHttpRequest to Post HTML Form.

  3. Limitation of this solution: As pointed out by Justin Blank and Thomas Munk (see their comments), FormData is not supported by IE9 and lower, and default browser on Android 2.3.

rogerdpack
  • 50,731
  • 31
  • 212
  • 332
oHo
  • 41,098
  • 25
  • 141
  • 183
  • 1
    The only thing about this is that I think FormData is not available in IE 9, so it's not going to be usable for a lot of people without a polyfill. developer.mozilla.org/en-US/docs/Web/API/FormData – Justin Blank Jul 09 '14 at 14:19
  • Thanks @ThomasMunk for your link :-) We see that `FormData` is supported by many browsers except IE9 and Android 2.3 (and OperaMini but this last is not widely used). Cheers ;-) – oHo Oct 24 '14 at 07:56
26

NO PLUGINS NEEDED!

Select the below code and drag that into in BOOKMARK BAR (if you don't see it, enable from Browser Settings), then EDIT that link :

enter image description here

javascript:var my_params = prompt("Enter your parameters", "var1=aaaa&var2=bbbbb"); var Target_LINK = prompt("Enter destination", location.href); function post(path, params) { var xForm = document.createElement("form"); xForm.setAttribute("method", "post"); xForm.setAttribute("action", path); for (var key in params) { if (params.hasOwnProperty(key)) { var hiddenField = document.createElement("input"); hiddenField.setAttribute("name", key); hiddenField.setAttribute("value", params[key]); xForm.appendChild(hiddenField); } } var xhr = new XMLHttpRequest(); xhr.onload = function () { alert(xhr.responseText); }; xhr.open(xForm.method, xForm.action, true); xhr.send(new FormData(xForm)); return false; } parsed_params = {}; my_params.split("&").forEach(function (item) { var s = item.split("="), k = s[0], v = s[1]; parsed_params[k] = v; }); post(Target_LINK, parsed_params); void(0);

That's all! Now you can visit any website, and click that button in BOOKMARK BAR!


NOTE:

The above method sends data using XMLHttpRequest method, so, you have to be on the same domain while triggering the script. That's why I prefer sending data with a simulated FORM SUBMITTING, which can send the code to any domain - here is code for that:

 javascript:var my_params=prompt("Enter your parameters","var1=aaaa&var2=bbbbb"); var Target_LINK=prompt("Enter destination", location.href); function post(path, params) {   var xForm= document.createElement("form");   xForm.setAttribute("method", "post");   xForm.setAttribute("action", path); xForm.setAttribute("target", "_blank");   for(var key in params) {   if(params.hasOwnProperty(key)) {        var hiddenField = document.createElement("input");      hiddenField.setAttribute("name", key);      hiddenField.setAttribute("value", params[key]);         xForm.appendChild(hiddenField);     }   }   document.body.appendChild(xForm);  xForm.submit(); }   parsed_params={}; my_params.split("&").forEach(function(item) {var s = item.split("="), k=s[0], v=s[1]; parsed_params[k] = v;}); post(Target_LINK, parsed_params); void(0); 
T.Todua
  • 44,747
  • 17
  • 195
  • 185
  • For Mozilla, Can I do something similar to this? –  Jul 29 '16 at 05:46
  • I didn't and I couldn't :| I don't have 125 reps :| And if you see my profile you will see I have 136 up votes :| Even after I get the permission to downvote, I will avoid it unless it is neccessary :| –  Jul 29 '16 at 09:20
  • 19
    And your question really doesn't answer what OP has asked for. BookMarking a HTTP Request... !? I don't see any point relating `XmlHttpRequest` in your answer :| –  Jul 29 '16 at 09:27
  • 2
    awesome. just wanted some relation while reviewing since it was an answer . now it is an answer plus a gr8 tip for all who drop by. i've reverted votes. cheers – Iceman Aug 19 '16 at 11:06
6

I have faced similar problem, using the same post and and this link I have resolved my issue.

 var http = new XMLHttpRequest();
 var url = "MY_URL.Com/login.aspx";
 var params = 'eid=' +userEmailId+'&amp;pwd='+userPwd

 http.open("POST", url, true);

 // Send the proper header information along with the request
 //http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
 //http.setRequestHeader("Content-Length", params.length);// all browser wont support Refused to set unsafe header "Content-Length"
 //http.setRequestHeader("Connection", "close");//Refused to set unsafe header "Connection"

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

This link has completed information.

Tam
  • 3,153
  • 3
  • 30
  • 50
5
var util = {
    getAttribute: function (dom, attr) {
        if (dom.getAttribute !== undefined) {
            return dom.getAttribute(attr);
        } else if (dom[attr] !== undefined) {
            return dom[attr];
        } else {
            return null;
        }
    },
    addEvent: function (obj, evtName, func) {
        //Primero revisar attributos si existe o no.
        if (obj.addEventListener) {
            obj.addEventListener(evtName, func, false);

        } else if (obj.attachEvent) {
            obj.attachEvent(evtName, func);
        } else {
            if (this.getAttribute("on" + evtName) !== undefined) {
                obj["on" + evtName] = func;
            } else {
                obj[evtName] = func;
            }

        }

    },
    removeEvent: function (obj, evtName, func) {
        if (obj.removeEventListener) {
            obj.removeEventListener(evtName, func, false);
        } else if (obj.detachEvent) {
            obj.detachEvent(evtName, func);
        } else {
            if (this.getAttribute("on" + evtName) !== undefined) {
                obj["on" + evtName] = null;
            } else {
                obj[evtName] = null;
            }
        }

    },
    getAjaxObject: function () {
        var xhttp = null;
        //XDomainRequest
        if ("XMLHttpRequest" in window) {
            xhttp = new XMLHttpRequest();
        } else {
            // code for IE6, IE5
            xhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        return xhttp;
    }

};

//START CODE HERE.

var xhr = util.getAjaxObject();

var isUpload = (xhr && ('upload' in xhr) && ('onprogress' in xhr.upload));

if (isUpload) {
    util.addEvent(xhr, "progress", xhrEvt.onProgress());
    util.addEvent(xhr, "loadstart", xhrEvt.onLoadStart);
    util.addEvent(xhr, "abort", xhrEvt.onAbort);
}

util.addEvent(xhr, "readystatechange", xhrEvt.ajaxOnReadyState);

var xhrEvt = {
    onProgress: function (e) {
        if (e.lengthComputable) {
            //Loaded bytes.
            var cLoaded = e.loaded;
        }
    },
    onLoadStart: function () {
    },
    onAbort: function () {
    },
    onReadyState: function () {
        var state = xhr.readyState;
        var httpStatus = xhr.status;

        if (state === 4 && httpStatus === 200) {
            //Completed success.
            var data = xhr.responseText;
        }

    }
};
//CONTINUE YOUR CODE HERE.
xhr.open('POST', 'mypage.php', true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');


if ('FormData' in window) {
    var formData = new FormData();
    formData.append("user", "aaaaa");
    formData.append("pass", "bbbbb");

    xhr.send(formData);

} else {

    xhr.send("?user=aaaaa&pass=bbbbb");
}
toto
  • 1,122
  • 2
  • 13
  • 26
  • 1
    Hello Hugo, This code is to send data or file with progress upload if browser support it. included all possible events and compatibility browser. It try use the most new object class from browser. It help you? – toto Dec 08 '16 at 17:24
4

Try to use json object instead of formdata. below is the code working for me. formdata doesnot work for me either, hence I came up with this solution.

var jdata = new Object();
jdata.level = levelVal; // level is key and levelVal is value
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "http://MyURL", true);
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.send(JSON.stringify(jdata));

xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      console.log(this.responseText);
    }
}
Duck
  • 32,792
  • 46
  • 221
  • 426
Brainwash
  • 127
  • 1
  • 7
3

There's some duplicates that touch on this, and nobody really expounds on it. I'll borrow the accepted answer example to illustrate

http.open('POST', url, true);
http.send('lorem=ipsum&name=binny');

I oversimplified this (I use http.onload(function() {}) instead of that answer's older methodology) for the sake of illustration. If you use this as-is, you'll find your server is probably interpreting the POST body as a string and not actual key=value parameters (i.e. PHP won't show any $_POST variables). You must pass the form header in to get that, and do that before http.send()

http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');

If you're using JSON and not URL-encoded data, pass application/json instead

Machavity
  • 28,730
  • 25
  • 78
  • 91
3

This helped me as I wanted to use only xmlHttpRequest and post an object as form data:

function sendData(data) {
  var XHR = new XMLHttpRequest();
  var FD  = new FormData();

  // Push our data into our FormData object
  for(name in data) {
    FD.append(name, data[name]);
  }

  // Set up our request
  XHR.open('POST', 'https://example.com/cors.php');

  // Send our FormData object; HTTP headers are set automatically
  XHR.send(FD);
}

https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript

M3RS
  • 4,254
  • 1
  • 24
  • 40
1

Just for feature readers finding this question. I found that the accepted answer works fine as long as you have a given path, but if you leave it blank it will fail in IE. Here is what I came up with:

function post(path, data, callback) {
    "use strict";
    var request = new XMLHttpRequest();

    if (path === "") {
        path = "/";
    }
    request.open('POST', path, true);
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
    request.onload = function (d) {
        callback(d.currentTarget.response);
    };
    request.send(serialize(data));
}

You can you it like so:

post("", {orem: ipsum, name: binny}, function (response) {
    console.log(respone);
})
Sebastian Td
  • 134
  • 1
  • 7
1

Short & modern

You can catch form input values using FormData and send them by fetch

fetch(form.action, {method:'post', body: new FormData(form)});

function send() {
  let form = document.forms['inputform'];
  fetch(form.action, {method:'post', body: new FormData(form)});
}
<form name="inputform" action="somewhere" method="post">
  <input               value="person" name="user">
  <input type="hidden" value="password" name="pwd">
  <input               value="place" name="organization">
  <input type="hidden" value="key" name="requiredkey">
</form>

<!-- I remove type="hidden" for some inputs above only for show them --><br>
Look: chrome console>network and click <button onclick="send()">send</button>
Kamil Kiełczewski
  • 53,729
  • 20
  • 259
  • 241