Introduction

Ajax stands for “Asynchronous JavaScript + XML” (although JSON is mostly used today), and represents a group of technologies intended for dynamic creation of Web pages. By using AJAX, we improve the quality of interactivity with the user, with the desire to make it as similar as possible to desktop applications (according to the speed of interaction). The idea behind Ajax is that the page on which the Web application takes place is loaded only once, and that all further communication with the server is performed asynchronously without blocking the interface and without reloading the entire page. Asynchronous behavior means that after the user interacts with the interface, the request to the server is accepted by JavaScript and the XMLHttpRequest object, which in the background sends requests to the server and displays the results when they are available, while the user can continue working in the meantime.
Ajax is not without flaws, since Ajax pages are dynamically generated the biggest problem for sites is search engine optimization. Search engines often cannot interpret the site well, which leads to problems in indexing the sites. A similar problem exists with page traffic analysis tools, because a user can spend a whole day on one Ajax page, and classic traffic analysis tools will interpret this as one page view.
XMLHttpRequest object
XMLHttpRequest is the foundation of AJAX and is a JavaScript object used to send HTTP requests. Designed by Microsoft and then accepted by other major browsers and in 2014 became a standard in W3C.
XHR Object Properties
- state 0: initial value of object after creation
- state 1: open() method executed successfully; at this stage request headers can be set with the setRequestHeader()
- state 2: all response headers have arrived
- state 3: begins reading the response data part
- state 4: The response data part was successfully loaded or an error occurred
function
in that case
XHR Object Methods
- Method: POST, GET, HEADER, PUT, DELETE
- ULR is the url of the server to which the request is sent
- Asynchrony can be true or false depending on whether the request is implemented asynchronously or synchronously
- Username and password are optional arguments that are specified if they are required to access the server
Procedure
a) Creating an object
It is created by calling the XMLHttpRequest constructor:
|
1 |
var xhr = new XMLHttpRequest(); |
b) Event handler and callback function
Events (events) related to the XHR object
Events related to an XHR object can be:
|
1 2 3 4 5 |
xhr.onreadystatechange = function(){ if (this.readyState == 4 && this.status == 200) { // Process the server response here. } }; |
|
1 2 3 4 |
xhr.addEventListener(error, function(e) { var error = e.error; console.log(error); }); |
|
1 2 3 4 5 6 |
xhr.addEventListener("load", function(){ if (this.status < 400) { // Process the server response here. } else { new Error("Request failed: " + xhr.statusText); }, false); |
c) Defining connection parameters
After creating the XMLHttpRequest object, it is necessary to define basic parameters for communication. This method does not send a request to the web server, but saves its arguments for sending a request later.
|
1 |
xhr.open(method,url,async,username,password) |
Description of method arguments:
-
Method
Methods that can be used are: POST, GET, HEADER, PUT, DELETE.
GET method sends request and data through url, with it the request can be cached, the request remains in the history of the browser and can be bookmarked. The downside is the limited size of data that can be passed through the URL, as well as the visibility of the data in the URL (read “insecurity“). Which is why this method is not used for sending important data.The POST method does not send data through the URL, but through the send() attribute of the method, so it is safer and is used when confidential data (usually entered by the user) needs to be sent. The POST method is also used when a larger amount of data needs to be sent, given that it does not have a limited data size, as is the case with the GET method. However, with this method, the request cannot be cached, it does not remain in the browser’s history, so it cannot be bookmarked either.
The HEAD method asks the server for headers from the specified URL without the document content (used, for example, to check the modification date of the resource). -
URL
The ULR is the url of the server to which the request is sent
-
Asynchrony of requests
This parameter defines the asynchrony of the request. It can be true or false. If omitted or defined as TRUE, then the request is asynchronous.
NOTE:
The XMLHttpRequest request can also be synchronous, but this is not recommended because if the server does not send a response, the send() method can block the browser. There is no “magic button” that stops the XMLHttpRequest, and no maximum waiting time, so the JavaScript engine does not allow the execution of the request to be stopped once it has been sent. -
User Name and Password
Username and password are optional arguments that are specified if they are required to access the server
d) Definition of header data
Syntax
With the method “setRequestHeader()” we can define some values in the request header. It is most often used when sending data to the server with the POST method. The method parameter is in the form of a “key, value” pair.
|
1 |
xhr.setRequestHeader(key, value); |
NOTE:
The “setRequestHeader()” method must be placed between the open() and send() methods.
Application
Most often, data is sent through the parameter of the “setRequestHeader()” method, in which way the data is encoded.
|
1 |
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); |
What is encoding?
There are three ways it can be encoded:
control
The “application/x-www-form-urlencoded” content type is used in most cases, except for sending large amounts of binary data or text containing non-ASCII characters as it is inefficient for that. And “multipart/form-data” should be used for form submissions that contain files, non-ASCII data, and binary data.
e) Preparing data for sending
In the case of sending data, it is necessary to prepare the data in a form suitable for sending.
Serializing data into “query string”
a) Simple information
If the data is simple, it is sent as a query string consisting of name/value pairs separated by the “&” sign, where the names are separated from the values by the equal sign “=”, and if there isspecial characters those transferred to ASCII HEX values.
|
1 |
var data = "MyVariableOne=ValueOne&MyVariableTwo=ValueTwo"; |
b) Object
If it is an object/JSON, it must first be converted into a string.
|
1 |
var arr = JSON.stringify([ 'foo', 'bar' ]); // Returns: ["foo","bar"] |
After which encode the resulting string:
|
1 2 |
var encoArr = encodeURIComponent(arr) // Returns: %5B%22foo%22%2C%22bar%22%5D var url = 'http://example.com/?data=' + encoArr ; |
Decoding and encoding can be checked through online services such as https://www.freeformatter.com/url-encoder.html or http://www.url-encode-decode.com/.
Example
This snippet has similar functionality to the jQuery method serialize()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
function serialize(form) { var field, l, s = []; if (typeof form == 'object' && form.nodeName == "FORM") { var len = form.elements.length; for (var i=0; i<len; i++) { field = form.elements[i]; if (field.name && !field.disabled && field.type != 'file' && field.type != 'reset' && field.type != 'submit' && field.type != 'button') { if (field.type == 'select-multiple') { l = form.elements[i].options.length; for (var j=0; j<l; j++) { if(field.options[j].selected) s[s.length] = encodeURIComponent(field.name) + "=" + encodeURIComponent(field.options[j].value); } } else if ((field.type != 'checkbox' && field.type != 'radio') || field.checked) { s[s.length] = encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value); } } } } return s.join('&').replace(/%20/g, '+'); } |
Serializing data into an array
This snippet has similar functionality to the jQuery method serializeArray()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
function serializeArray(form) { var field, l, s = []; if (typeof form == 'object' && form.nodeName == "FORM") { var len = form.elements.length; for (var i=0; i<len; i++) { field = form.elements[i]; if (field.name && !field.disabled && field.type != 'file' && field.type != 'reset' && field.type != 'submit' && field.type != 'button') { if (field.type == 'select-multiple') { l = form.elements[i].options.length; for (j=0; j<l; j++) { if(field.options[j].selected) s[s.length] = { name: field.name, value: field.options[j].value }; } } else if ((field.type != 'checkbox' && field.type != 'radio') || field.checked) { s[s.length] = { name: field.name, value: field.value }; } } } } return s; } |
f) Sending requests
Initiating the connection of a prepared and defined request with the server is done with the send() method. We can use the send(attribute) method attribute to send data to the server. It is precisely with the POST method that this is the main principle of sending data. We simply send all “preparation” data as an attribute of the “send” method. However, since with the GET method we send all the information through the URL, we do not use this possibility of sending through the attribute, but define the attribute with null send(null) or simply do not fill it.
g) Server response
Request status
The status of our request as a server response is accessed using the status
property of the XMLHttpRequest object
|
1 |
xhr.status |
to the status text with:
|
1 |
xhr.statusText |
String response
The server response in the form of a “string” is accessed via the responseText
property
|
1 |
xhr.responseText |
NOTE:
XMLHttpRequest does not have a direct property for server response in JSON format, so it is necessary to parse the response:
JSON.parse(xhr.responseText);
XML response
A server response that is some XML is accessed with responseXML
|
1 |
xhr.responseXML |
HTTP server response header
Access to all headers returned by the web server is with the help of the method getResponseHeader() :
|
1 |
xhr.getResponseHeader() |
Examples
EXPLANATION:
In the examples, I use the online resource myjson.com to quickly generate a REST endpoint.
a) Getting data from the server
Example No. 1
I access the JSON file saved on the site http://myjson.com/ via the endpoint: https://api.myjson.com/bins/erxi9. With an ajax request to the endpoint I get the following content:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
[ { ime: "Pera", pozicija: "direktor" }, { ime: "Dragan", pozicija: "poslovodja" }, { ime: "Milan", pozicija: "radnik" }, { ime: "Zoran", pozicija: "radnik" }, { ime: "Dejan", pozicija: "radnik" } ] |
In this example, all persons who satisfy the selected position are printed:
See the Pen Promise primer by Web programming (@chos) on CodePen.
Example No. 2
For this example I am using the generated endpoint https://api.myjson.com/bins/amz5t.
See the Pen Ajax GET by Web Programming (@chos) on CodePen.
b) Sending data to the server
Example
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var newName = 'John Smith'; var xhr = new XMLHttpRequest(); xhr.open('POST', 'myservice/username?id=some-unique-id'); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onload = function() { if (xhr.status === 200 && xhr.responseText !== newName) { alert('Something went wrong. Name is now ' + xhr.responseText); } else if (xhr.status !== 200) { alert('Request failed. Returned status of ' + xhr.status); } }; xhr.send(encodeURI('name=' + newName)); |
Example: sending data from a form
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
document.getElementById("myform").onsubmit = function(e) { e.preventDefault(); var f = e.target, formData = '', xhr = new XMLHttpRequest(); // fetch form values for (var i = 0, d, v; i < f.elements.length; i++) { d = f.elements[i]; if (d.name && d.value) { v = (d.type == "checkbox" || d.type == "radio" ? (d.checked ? d.value : '') : d.value); if (v) formData += d.name + "=" + escape(v) + "&"; } } xhr.open("POST", f.action); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8"); xhr.send(formData); } |
c) Sending files to the server
|
1 2 3 4 5 |
var file = document.getElementById('test-input').files[0]; var xhr = new XMLHttpRequest(); xhr.open('POST', 'myserver/uploads'); xhr.setRequestHeader('Content-Type', file.type); xhr.send(file); |
