PROWAREtech
JavaScript: AJAX Library
Note: if looking for an AJAX library to use with React then see AJAX Library for React.
This is what AJAX looks like without a library to simplify it.
<!DOCTYPE html>
<!-- basic_ajax.html -->
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Basic AJAX Example</title>
<style>
pre {
white-space: normal;
}
</style>
<script type="text/javascript">
function getFile(file) {
var xmlobj;
if (typeof XMLHttpRequest != "undefined") {
xmlobj = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
var aVersions = ["MSXML2.XMLHttp.5.0", "MSXML2.XMLHttp.4.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp", "Microsoft.XMLHttp"];
for (var i = 0; i < aVersions.length; i++) {
try {
xmlobj = new ActiveXObject(aVersions[i]);
break;
} catch (err) {
}
}
}
if(xmlobj) {
xmlobj.onreadystatechange = function () {
if (xmlobj.readyState == 4 && xmlobj.status == 200) {
document.getElementById("html").innerText = xmlobj.responseText;
}
}
xmlobj.open("get", file, true);
xmlobj.send(null);
}
return false;
}
</script>
</head>
<body>
<pre id="html"></pre>
<a onclick="return getFile('Lorem.txt');" href="#">Get the Lorem.txt file</a>
</body>
</html>
Here is the above file using the AJAX library (ajaxlib.js) that follows.
<!DOCTYPE html>
<!-- ajax_lib.html -->
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>AJAX Library Example</title>
<style>
pre {
white-space: normal;
}
</style>
<script src="ajaxlib.js"></script>
</head>
<body>
<pre id="txt"></pre>
<a onclick="return ajax({
path: 'Lorem.txt',
onsuccess: function(responseText) {
document.getElementById('txt').innerText = responseText;
}
});" href="#">Get the Lorem.txt file using ajaxlib.js</a>
</body>
</html>
ajaxlib.js
These following are functions commonly used in AJAX. The ajax
function submits the AJAX request. The buildFormData
function returns a FormData
object
or a string built from a form object to use in the body of the post (data:
of the ajax()
function request object). It can also calculate the size of the data in the form when specifying true
for the returnSizeOnly
parameter. Make sure to set the form's enctype
attribute otherwise the buildFormData
function won't be able to work with "multipart/form-data" forms.
The ajax
function calls a method function of the request object — if specified — with the percentage completion of the upload so that a progress indicator can be displayed for the user.
This code has been tested on IE6 and newer browsers like Chrome, Safari and Firefox.
// ajaxlib.js
// add additional, custom fields here if so desired;
// returnSizeOnly=true will calculate the size of the form's data
function buildFormData(form, returnSizeOnly) {
var size = 0;
var params = new Array();
var fd;
if (!returnSizeOnly && form.enctype.toLowerCase() == "multipart/form-data" && typeof FormData != "undefined") {
fd = new FormData();
}
var len = form.elements.length;
for (var i = 0; i < len; i++) {
var field = form.elements[i];
if (field.name && field.name.length > 0) {
switch (field.type) {
case "select-one":
case "select-multiple":
if (field.name.length) {
var j, optLen;
for (j = 0, optLen = field.options.length; j < optLen; j++) {
option = field.options[j];
if (option.selected) {
var optValue = "";
if (option.hasAttribute) {
optValue = (option.hasAttribute("value") ? option.value : option.text);
} else {
optValue = (option.attributes["value"].specified ? option.value : option.text);
}
if (fd) {
fd.append(field.name, optValue);
}
else {
params.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(optValue));
}
size += optValue.length;
}
}
}
break;
case "submit":
case "reset":
case "button":
case undefined:
break;
case "file":
for (var j = 0; j < field.files.length; j++) {
if (fd) {
fd.append(field.name, field.files[j], field.files[j].name)
}
size += field.files[j].size;
}
break;
case "checkbox":
case "radio":
if (!field.checked) {
break;
}
default:
if (fd) {
fd.append(field.name, field.value)
}
else {
params.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value));
}
size += field.value.length;
}
}
}
return (returnSizeOnly ? size : (fd ? fd : params.join("&")));
}
/*
request = {
verb: "GET POST PUT DELETE etc.",
path: "",
contentType: "application/json; charset=utf-8, application/x-www-form-urlencoded; charset=utf-8, etc.",
headers: {"header1":"value1","header2":"value2"},
data: "string" or FormData,
onprogress: function,
onsuccess: function,
onfailure: function
};
*/
function ajax(request) {
if (typeof request != "object") { request = {}; }
var func = "function";
var undef = "undefined";
var xmlobj;
if (typeof XMLHttpRequest != undef) { // must use typeof operator for compatibility reasons
xmlobj = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
var aVersions = ["MSXML2.XMLHttp.5.0", "MSXML2.XMLHttp.4.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp", "Microsoft.XMLHttp"];
for (var i = 0; i < aVersions.length; i++) {
try {
xmlobj = new ActiveXObject(aVersions[i]);
break;
} catch (err) {
//void
}
}
}
var hasFailure = (typeof request.onfailure == func);
if (!xmlobj) {
if (hasFailure) {
request.onfailure(0, ""); // send a status of zero for this error
}
return false;
}
var hasProgess = (typeof request.onprogress == func);
if (hasProgess) {
xmlobj.onprogress = function (event) {
if (event.lengthComputable) {
request.onprogress(Math.floor(event.loaded / event.total * 100));
}
};
xmlobj.upload.onprogress = function (event) {
request.onprogress(Math.floor(event.loaded / event.total * 100));
};
}
xmlobj.onreadystatechange = function () {
if (xmlobj.readyState == 4) {
if (hasProgess) {
request.onprogress(false);
}
if (xmlobj.status == 200) {
if (typeof request.onsuccess == func) {
request.onsuccess((request.responseType && request.responseType == "arraybuffer") ? xmlobj.response : xmlobj.responseText);
}
}
else if (hasFailure) {
request.onfailure(xmlobj.status, xmlobj.statusText);
}
}
};
xmlobj.open(request.verb || "get", request.path || window.document.location.pathname, true);
if (request.responseType) {
xmlobj.responseType = request.responseType;
}
if (request.contentType) {
if (typeof FormData == undef || !(request.data instanceof FormData)) {
xmlobj.setRequestHeader("Content-Type", request.contentType);
}
}
if (request.headers) {
for (var n in request.headers) {
xmlobj.setRequestHeader(n, request.headers[n]);
}
}
xmlobj.send(request.data || null);
return false; // to prevent forms and links from submitting
}
Here is example code using the above AJAX library.
// get the current page
var request = {
onsuccess: function (responseText) { alert(responseText); }
};
ajax(request);
// get /api/customers data
var request = {
path: "/api/customers",
onsuccess: function (responseText) { var customers = JSON.parse(responseText); }
};
ajax(request);
// post a form
var form = document.getElementById("form-id");
function progress(percent) {
var progressBar = document.getElementById("progress-bar");
progressBar.style.backgroundColor = "red";
progressBar.style.height = "16px";
if(percent) {
progressBar.innerText = progressBar.style.width = percent + "%";
}
else {
progressBar.innerText = progressBar.style.width = "";
}
}
function success(responseText) {
alert(responseText);
}
var request = {
verb: form.method,
path: form.action,
contentType: "application/x-www-form-urlencoded; charset=utf-8",
data: buildFormData(form),
headers: {"Authorization":"auth token","referer":"http://localhost/index.html"},
onprogress: progress,
onsuccess: success
};
ajax(request);
// post a multipart/form-data form
var form = document.getElementById("form-id");
function progress(percent) {
var progressBar = document.getElementById("progress-bar");
progressBar.style.backgroundColor = "green";
progressBar.style.height = "20px";
if(percent) {
progressBar.innerText = progressBar.style.width = percent + "%";
}
else {
progressBar.innerText = progressBar.style.width = "";
}
}
function success(responseText) {
alert(responseText);
}
function failure(status, text) {
alert(status + ": " + text);
}
var request = {
verb: form.method,
path: form.action,
data: buildFormData(form),
onprogress: progress,
onsuccess: success,
onfailure: failure
};
ajax(request);
// post json and get json returned
ajax({
verb: "post",
path: "/api/addcustomer",
contentType: "application/json",
data: JSON.stringify({ firstname: form.firstname, lastname: form.lastname }),
onprogress: function(percent) { /* do something */ },
onsuccess: function(responseText) { var obj = JSON.parse(responseText); },
onfailure: function(status, text) { alert(status + ": " + text); }
});
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="ajaxlib.js"></script> <!--download from above-->
</head>
<body>
<pre id="html"></pre>
<a onclick="return ajax({ onsuccess: function (res) { document.getElementById('html').innerText = res; } });" href="#">get the current page</a>
<form enctype="multipart/form-data" action="/" method="post" onsubmit="return ajax({
verb: this.method,
path: this.action,
contentType: this.enctype,
data: buildFormData(this),
onprogress: function (percent) {
if (percent)
document.getElementById('progress').style.width = percent + '%';
else
document.getElementById('progress').style.width = 0;
},
onsuccess: function (res) {
alert(res);
},
onfailure: function(status, text) {
alert(status + ' ' + text);
}
});">
<input type="text" name="name" />
<input type="file" name="file" multiple />
<input type="submit" value="post to home page" />
</form>
<div id="progress" style="width:0;height:16px;background-color:red;"></div>
</body>
</html>
Here is a simple Node.js server that serves static files and echos data that is posted to it. It is useful for testing AJAX code. Learn more about Node.js.
var fs = require("fs");
const http = require("http");
const server = http.createServer().listen(8000);
console.log("listening on port 8000");
server.on("request", function (request, response) {
if (request.method == "POST") {
var body = "";
request.on("data", function (data) {
body += data.toString();
});
request.on("end", function () {
console.log(body);
var bodyArray = body.split('&');
var obj = {};
for(var i = 0; i < bodyArray.length; i++) {
var temp = bodyArray[i].split('=');
if(temp.length == 2)
obj[temp[0]] = decodeURIComponent(temp[1].replace(/\+/g, "%20"));
else
obj[temp[0]] = null;
}
// ECHO THE DATA BACK TO THE CLIENT
response.writeHead(200, {"Content-Type":"application/json"});
response.write(JSON.stringify(obj));
response.end();
});
}
else if (request.method == "GET") { // SERVE STATIC HTML FILES
console.log(request.url);
var file = request.url.substring(1, request.url.length);
if(file.length == 0)
file = "index.html";
fs.readFile(file, function (err, data) {
if (!err) {
response.writeHead(200, {"Content-Type":"text/html"});
response.end(data.toString('utf8'));
}
else {
response.writeHead(404, {"Content-Type":"text/plain"});
response.end(`path ${request.url} not found`);
}
});
}
else {
response.writeHead(405, {"Content-Type":"text/plain"});
response.end(`method ${request.method} not allowed`);
}
});
This file was used with the above node.js server.
<!DOCTYPE html>
<!-- ajax_lib_form.html -->
<html lang="en">
<head>
<title>AJAX Library Example Form</title>
<script src="ajaxlib.js"></script>
<script type="text/javascript">
function submitForm(form) {
return ajax({
verb: form.method,
path: form.action,
contentType: form.enctype,
data: buildFormData(form),
onsuccess: function(responseText) {
document.getElementById('txt').innerText = responseText; // this server will return JSON
},
onprogress: function(percentage) {
if (percentage) {
document.getElementById('percent').innerText = percentage + '%';
}
},
onfailure: function(errorCode, errorText) {
alert(errorCode + ': ' + errorText);
}
});
}
</script>
</head>
<body>
<pre id="txt"></pre>
<form action="/" method="POST" enctype="application/x-www-form-urlencoded" onsubmit="return submitForm(this);">
<input type="text" name="name" placeholder="enter name" /><br />
<input type="text" name="address" placeholder="enter address" /><br />
<input type="text" name="state" placeholder="enter state" /><br />
<input type="text" name="zip" placeholder="enter zip" /><br />
<input type="submit" />
</form>
<div id="percent"></div>
</body>
</html>