Media Temple Hosting

Building an Ajax Application with Progressive Enhancement

Building an Ajax Application with Progressive EnhancementIf you’ve done your best to keep up with web development trends over the past five years or more, then it’s likely that you’re familiar with the concept of Progressive Enhancement. I’m not going to provide an explanation of that technique here, but instead, I thought I would demonstrate using a small Ajax-driven page how progressive enhancement can be implemented.

The mini-app we’ll be building in this tutorial is an employee information page. It will consist of a series of links at the top of the page that will determine what employee info is displayed in the content area. The information will be held inside of include files, to simplify the process (as opposed to a database or XML file which might be more practical in a real-world app). Although we’re going to use Ajax to display the information, we’re going to ensure that the same information is displayed even when the user is visiting the page without JavaScript capabilities.

View the Page We’ll Be Building

Step 1: Create the Primary PHP-driven Web Page

Since this tutorial is for the purpose of demonstrating progressive enhancement, the first thing we need to do is create the entire, fully-functional web page using a back-end technology. In this example, I’m using PHP, so a little bit of knowledge in that area would be helpful if you want to follow along with every step. From there, we’ll progressively enhance our mini-app with JavaScript and Ajax.

Here is the code for our main page:

<ul>
	<li><a href="?view=employee1">Employee 1</a></li>
	<li><a href="?view=employee2">Employee 2</a></li>
	<li><a href="?view=employee3">Employee 3</a></li>
	<li><a href="?view=employee4">Employee 4</a></li>
	<li><a href="?view=employee5">Employee 5</a></li>
</ul>

<div id="employee-info">
<?php include "employees.php"; ?>
</div>

Ideally, we would create the page so that the number of employees is flexible, but that would require some more complex PHP code. Since this tutorial is not about PHP, but about progressive enhancement, I’m simplifying things for demonstration purposes.

Three things to note about the above code:

  • Each link points to the same page with a query string value appended to identify which employee link is clicked
  • The content section is identified by a unique ID
  • The content section is populated by a PHP include

Step 2: Create the employee.php Include File

The employee.php include file is the engine that runs the page. We want the output of this file to change depending on what link is clicked. But we also want the employee.php file to be abstracted from the data itself, so we can update the data through a more practical means. In this example, as mentioned, I’m using separate include files for each employee. Most likely this information would be contained in a database or in an XML file, but I’m simplifying this to make things easier.

Let’s take a look at the code in our primary include file:

<?php
if (isset($_GET["view"])) {
	switch ($_GET["view"]) {
		case "employee1":
			include "employee1.html";
		break;
		case "employee2":
			include "employee2.html";
		break;
		case "employee3":
			include "employee3.html";
		break;
		case "employee4":
			include "employee4.html";
		break;
		case "employee5":
			include "employee5.html";
		break;
		default:
		?>
			<p>That employee doesn't exist.</p>
		<?php
		break;
		}
	} else {
	?>
	<p>Click a link to view information about an employee.</p>
<?php
}
?>

The above code is fairly straightforward, and shouldn’t require much explanation for even beginning PHP developers. The first line checks to see if the “view” query string variable has been set. If it has, then a switch statement is initialized that includes a different file depending on the value of the query string. There is also a default for the switch statement, just in case the query string is “hacked”. Finally, the last part of the code displays a generic message if the page is visited with no query string variable.

Populating the different employee include files is just a matter of creating them and putting in the necessary markup and data. Again, this is not necessarily the ideal method to store this information, and you certainly would not want to store sensitive information in this manner, but it works well for the purpose of this tutorial.

Each individual employee include file will look something like this:

<h2>Employee #1</h2>
<p>Information for employee #1 goes here.</p>

After setting up all five employee include files, our mini-app is now fully functional.

View the PHP-only Demo Page

Step 3: Intercept Mouse Clicks with JavaScript

Since our page is fully functional with conventional back-end methods, the content will be accessible to virtually all visitors, regardless of their platform or browser limitations. Now we can safely enhance the page with some JavaScript. The first thing we want to do is loop through the links in the navigation section and write some code that will intercept mouse clicks and thus prevent the page from being reloaded. Here’s the code:

var myLinksCollection = document.getElementsByTagName("a");

for (i=0;i<myLinksCollection.length;i++) {
	myLinksCollection[i].onclick = function() {
		return false;
	}
}

The first line of code creates an array holding all the anchor elements on the page. Then, the for loop iterates through the anchor elements and attaches an onclick event handler to each one. An anonymous function runs when a link is clicked, and the return false statement ensures that the location in the href attribute is not visited.

Also, to ensure the onclick handler is applied only to the links in the navigation section, we can add an if statement that looks for a particular string in the href value of each link of the page, like this:

for (i=0;i<myLinksCollection.length;i++) {
	myLinksCollection[i].onclick = function() {
		if (this.href.indexOf("view=") !== -1) {
			return false;
		}
	}
}

Now the onclick event will only be added to links that have the string “view=” in their href attribute. There are other ways to limit what is affected in our for loop, but this will suffice to accomplish what we want.

Step 4: Identify Which Link Was Clicked

The loop in the previous section doesn’t accomplish anything — other than intercepting the mouse click. Inside the loop, we’ll add two lines of code to identify which link is being clicked. Now the loop looks like this:

for (i=0;i<myLinksCollection.length;i++) {
	myLinksCollection[i].onclick = function() {
		if (this.href.indexOf("view=") !== -1) {
			var clickedHREF = this.href;
			var clickedView = clickedHREF.split("view=");
			return false;
		}
	}
}

We have two new lines of code. The first line uses the this keyword (which represents the current object in JavaScript; in this case it’s the anchor that’s been clicked) to identify the value of the href attribute. Remember that each href value has a unique query string that identifies the desired employee info. After that value is placed in a variable, the second line uses the split method to divide the href value by means of the “view=” string, thus creating an array of two elements called “clickedView”.

Let’s view a demo page of what we have so far, which also includes an alert statement that spits out the value that we’ve extracted from the href attribute:

View Demo that Intercepts Mouse Clicks with JavaScript

Step 5: Display the Requested Content with Ajax

Now that we’ve written the code that identifies on the client side which link was clicked, we can alter the employee info content section through some Ajax code. We know, according to our PHP code, that the unique employee information is contained inside of separate include files whose names match the query string values that we’re extracting. This is done by design, because it allows us to easily load the required page without any further tests.

Here’s how our loop code will look after adding the new line of code that will trigger our Ajax request:

for (i=0;i<myLinksCollection.length;i++) {
	myLinksCollection[i].onclick = function() {
		if (this.href.indexOf("view=") !== -1) {
			var clickedHREF = this.href;
			var clickedView = clickedHREF.split("view=");
			ajaxInitiate(clickedView[1]+'.html');
			return false;
		}
	}
}

The new line is actually a function call that takes one argument. The argument is the extracted query string value plus “.html”, which amounts to a file name called “employee2.html” (or whatever employee was clicked).

The Ajax code that opens the desired file is complex, and an explanation of it is far beyond the scope of this simple tutorial. You’re welcome to check out my previous tutorials on Ajax using raw JavaScript that discuss in detail the code required:

Further reading on raw Ajax:

Of course, you could also implement Ajax code from your favourite JavaScript library, which would be a much easier method for those familiar with Ajax syntax in different libraries.

The final line of code that’s needed, which is added to our Ajax function, is a line that adds the content of the requested file into the “employee-info” <div>. The full Ajax code, plus the line that inserts the content of the file is included in the final demo page. The page also includes a “listener” function that allows multiple events to be inserted on the same page, and doesn’t run the code until the page is finished loading, similar to jQuery’s $(document).ready function.

View Final Demo

Conclusion — Plus Bonus Tutorial

This tutorial has served to demonstrate, using a real, albeit simple, Ajax application, the theoretical steps involved in creating a web page or web-based application with progressive enhancement. Progressive enhancement has its drawbacks, which I won’t go into detail about here, but I think it’s a technique worth considering for all future JavaScript development.

You may have noticed, however, that the final version of the application we built has a major weakness: When JavaScript is enabled, there is no way to link directly to a particular employee (like you would be able to do with the PHP-only version). Next week, I’ll post a quick follow-up bonus tutorial to demonstrate how to add deep linking that doesn’t require you to disable JavaScript.

No Responses

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field. If you use keywords, your comment will be deleted, or your name will be replaced with the alias from your email address. No foul language, please. Thank you for cooperating.

Instructions for code snippets: Wrap inline code in <code> tags; wrap blocks of code in <pre> and <code> tags. When you want your HTML to display on the page in a code snippet inside of <code> tags, make sure you use &lt; and &gt; instead of < and >, otherwise your code will be eaten by pink unicorns.