AJAX - Getting Interactive

Once you have an understanding of how to call data using XMLHttpRequest you'll probably want to make things a little more interactive. This simple example loads a JSON file but does so as the page loads, so we really don't get to appreciate the power of AJAX as an asynchronous technology.

Loading Data in Response to an Event

To create this example the HTML contains the following elements with ID selectors:

<p id="viewData">View Data</p>
<p id="dickens"></p>

We'll also be using the JSON file from the previous example:

{
  "Title1": "The Adventures of Oliver Twist",
  "Title2": "The Life and Adventures of Nicholas Nickleby",
  "Title3": "The Old Curiosity Shop",
  "Title4": "A Christmas Carol",
  "Title5": "David Copperfield",
  "Title6": "Bleak House",
  "Title7": "A Tale of Two Cities",
  "Title8": "Great Expectations"
}

We'll add an event to the viewData paragraph as follows:

document.getElementById('viewData').onclick = function(){
    console.info('test event');
}

To respect the DOM this is added at the bottom of the HTML just before the closing <body> tag ie:

...
<script>
document.getElementById('viewData').onclick = function(){
    console.info('test event');
}
</script>
</body>
</html>

Once you have used the console to test your event is triggered as expected, then add the following:

<script>
var myXHR=new XMLHttpRequest();
function showData() {
     var myJson  = JSON.parse(myXHR.responseText);
     document.getElementById('dickens').innerHTML = myJson.Title1;
}
document.getElementById('viewData').onclick = function(){
	myXHR.onload = showData;
	myXHR.open("GET","dickens.json", true);
	myXHR.send(null);
}
</script>
</body>

When the user clicks on the text of ID viewData the AJAX call is triggered in the background. Here is a working example.

Sending as well as Receiving

It is good to give as well as receive. So let's send some data through to a PHP script and see what we get in response.

This working example is what we aim to achieve. Notice how you can pick a review value from the radio buttons and asynchronously a call is sent to query the server and find out which films have been rated at that value. Notice no need to refresh the page - this is classic AJAX.

Firstly the HTML. This consists of a series of radio buttons and a <p> tag with an ID selector.

 <form>
  	<p>
  	    <label><input type="radio" name="filmRatings" value="1">1</label>
  	    <label><input type="radio" name="filmRatings" value="2">2</label>
  	    <label><input type="radio" name="filmRatings" value="3">3</label>
  	    <label><input type="radio" name="filmRatings" value="4">4</label>
  	    <label><input type="radio" name="filmRatings" value="5">5</label>
    </p>
  </form>
  <p id="films">
  
  </p>

Notice how the <form> does not have the traditional action and method attributes set, and that there is no submit button. That is because we don't need these as the request for data will be made asynchronously in the background with XMLHttpRequest.

Before we look at the Javascript required here, apologies but I am going to spin off briefly into the world of PHP. The PHP script I am using here is just a simple search query based on a value received via $_GET. It looks as follows:

require_once('includes/conn.inc.php'); 
$stmt = $mysqli->prepare("SELECT filmName FROM movies WHERE filmReview = ? ORDER BY filmName");
$stmt->bind_param('i', $_GET['filmReview']);
$stmt->execute(); 
$stmt->bind_result($filmName); 
$myArray = array();
while ($stmt->fetch()) {
	$myArray[] = $filmName;
}
echo json_encode($myArray);

Tip: Have a browse through the sections on working with PHP where there are plenty of examples of this kind of query.

The key thing here is that the PHP returns JSON. This is achieved by the use of the json_encode PHP method that takes a PHP array and converts it to JSON. In this case the PHP array is created by the database query. The JSON created is simply output to the screen via echo.

Notice how the query expects to receive a value via $_GET. We'll send that value via our XHR.

Probably the most complicated feature here is the Javascript to send the correct value to the PHP. I am going to use the DOM selector getElementsByName. This will select all elements with a given 'name' attribute. This is perfect for use with radio buttons as they should all share the same name. Once I have all these elements we'll loop round them. For example:

var filmRatings = document.getElementsByName('filmRatings');
for(var i = 0; i < filmRatings.length; i++){
   console.info(filmRatings[i].value);
}

What we'll place in the loop is an onclick event that will capture the value of the clicked radio button.

var filmRatings = document.getElementsByName('filmRatings');
var pickedValue;
for(var i = 0; i < filmRatings.length; i++){
	  filmRatings[i].onclick = function(){
		  pickedValue = this.value;
	  }
}

The above creates a variable called 'pickedValue'. We'll now send it to the PHP via XMLHttpRequest. As we are using a GET we'll create a query string in the myfile.php?name=value fashion. The PHP expects to receive a value of name 'filmReview'. Therefore are code with the XMLHttpRequest will appear as follows:

var filmRatings = document.getElementsByName('filmRatings');
var pickedValue;
for(var i = 0; i < filmRatings.length; i++){
	  filmRatings[i].onclick = function(){
		  pickedValue; = this.value;
		  myXHR.onload = showData;
		  myXHR.open("GET","search-by-rating-get.php?filmReview="+pickedValue, true);
		  myXHR.send(null);
	  }
}

Finally we'll want to do something with the returned data. As we have done previously we'll use JSON.parse() to convert the JSON data into an array.

Tip: JSON.parse() can be used to return either an object or an array.

The array data is looped around to extract the films that match the query and concatenated into a variable with lines breaks <br>. This is then assigned to the 'films' paragraph with a document.getElementById('films').innerHTML.

var myXHR=new XMLHttpRequest();
var filmRatings = document.getElementsByName('filmRatings');
var pickedValue;

function showData() {
			var myJson  = JSON.parse(myXHR.responseText);
			var noFilms = myJson.length;
			var newContent = "";
			for(var i=0; i<noFilms; i++){
				newContent += myJson[i];
				newContent += "<br>";
			}
			document.getElementById('films').innerHTML = newContent;
}

for(var i = 0; i < filmRatings.length; i++){
	  filmRatings[i].onclick = function(){
		  pickedValue = this.value;
		  myXHR.onload = showData;
		  myXHR.open("GET","search-by-rating-get.php?filmReview="+pickedValue, true);
		  myXHR.send(null);
	  }
}

Here again is the working example.

Sending via a POST

As you may know data can be sent to a web server via GET and POST. In the previous example we used GET but this example is going to use POST. To the end user it'll look exactly the same but we'll know there is a subtle difference here.

Here is the working example.

In this example we call a very similar PHP file to the GET example, the only difference been the use of $_POST ie:

require_once('includes/mbb.inc.php'); 
$stmt = $mysqli->prepare("SELECT filmName FROM movies WHERE filmReview = ? ORDER BY filmName");
$stmt->bind_param('i', $_POST['filmReview']);
$stmt->execute(); 
$stmt->bind_result($filmName); 
$myArray = array();
while ($stmt->fetch()) {
	$myArray[] = $filmName;
}
echo json_encode($myArray);

The Javascript also has some other subtle differences.

Firstly we send the data as an argument of the send() method. Again we send the variables as name / value pairs but this time we create a variable for them. The value of this variable takes the form of name1=value1&name2=value2.

Next ensure that 'POST' is used in the open method. Finally, as data sent via POST is placed in the HTTP headers we need to set the content type in the headers accordingly. This is done with:

myXHR.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

The amended example using a POST is therefore as follows:

var myXHR=new XMLHttpRequest();
var filmRatings = document.getElementsByName('filmRatings');
var pickedValue;
var sendVars;

function showData() {
			var myJson  = JSON.parse(myXHR.responseText);
			var noFilms = myJson.length;
			var newContent = "";
			for(var i=0; i<noFilms; i++){
				newContent += myJson[i];
				newContent += "<br>";
			}
			document.getElementById('films').innerHTML = newContent;
}

for(var i = 0; i < filmRatings.length; i++){
	  filmRatings[i].onclick = function(){
		  pickedValue = this.value;
		  sendVars = "filmReview="+pickedValue;
		  myXHR.onload = showData;
		  myXHR.open("POST","search-by-rating-post.php", true);
		  myXHR.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		  myXHR.send(sendVars);
	  }
}

Don't go away there is more we can learn about XMLHttpRequest to come.

Leave a Reply

*