The Single Page Application

The Web, as you undoubtedly are aware, was brought into being as a means of linking information. Fundamentally, the vision consisted of connecting individual “pages” of content, with the relationships between pages structured through the use of the hyperlink to allow navigation between pages of related content. Later, we introduced forms into the mix along with the idea of creating online applications. These applications continued to use the concept of pages, since that was how the Web worked. In an online application, the customer performs an action by clicking on a button or a link, a message is sent to the hosting server, and in response a new “page” is sent back and shown to the customer, updated to reflect the action taken.

This is the way that online applications have predominately worked for over 20 years, and while there are numerous advantages with this approach, when it comes to the increasing complexity of our online applications there are significant limitations as well:

  • Every time an action is performed, the whole page needs to be replaced, taking time
  • A large amount of redundant information is sent every time. Even if only one page element changes, the markup for the whole page is re-sent
  • If the customer had scrolled down the page to click on the link or action button, the page jumps back to the top, even if it’s really the same page

With relatively simple online applications, these issues are fairly minor, but as application complexity increases, these become major limitations to application usability. With native mobile applications or native desktop applications, these aren’t issues. As a result, there is an increasing push to bring more native-application-like capabilities to the browser, in the
form of the Single Page Application, also known as the Rich Internet Application. The SPA works by using Ajax to send small messages to the server, getting back just the information it needs to update only what’s needed.

The Traditional Approach: Submitting a Form

Lets take a closer look at the difference between the traditional approach to responding to the customer’s action versus the SPA approach, using a simple example which reflects the kind of actions that our traditional Web application might take. Consider the basic Web form below, which will form our starting point:

traditional_approach

The markup for such a screen might look like this:

<!DOCTYPE html>
<html>
	<head>
		<title>The Traditional Approach</title>
		<link href="shared/css/styles.css" rel="stylesheet">
	</head>
	<body>
		<form method="POST" action="traditional_approach_response.html">
		<h1>Manage Customers</h1>
			<fieldset>
				<label for="firstName">First Name</label>
				<input type="text" name="firstName" id="firstName" /><br />
				<label for="lastName">Last Name</label>
				<input type="text" name="lastName" id="lastName" /><br />
				<button name="addCustomer" id="addCustomer">Add Customer</button>
			</fieldset>
			<table>
				<thead>
					<tr>
						<th>Last Name</th>
						<th>First Name</th>
					</tr>
				</thead>
				<tbody>
					<tr>
						<td>Stark</td>
						<td>Ned</td>
					</tr>
					<tr>
						<td>Snow</td>
						<td>John</td>
					</tr>
				</tbody>
			</table>
		</form>
	</body>
</html>

The core parts of this application which control the interaction between the browser and the server are the <form> and <button> elements. The <form> element contains an action attribute that points to the “page” that is responsible for handling the form submission message to be sent. The button is responsible for initiating the form request. Together, these create a new page request that automatically includes the entered form information as part of the page request. The Web application server in turn returns all the HTML needed to draw out the complete page, this time with the new name included in the table markup.

The Single Page Application Approach: Sending a Message

Now take a look at how the same thing is done using the Single Page Application approach. Here’s our sample HTML:

<!DOCTYPE html>
<html>
	<head>
		<title>The Traditional Approach</title>
		<link href="shared/css/styles.css" rel="stylesheet">
	</head>
	<body>
		<form>
			<h1>Manage Customers</h1>
			<fieldset>
				<label for="firstName">First Name</label>
				<input type="text" name="firstName" id="firstName" /><br />
				<label for="lastName">Last Name</label>
				<input type="text" name="lastName" id="lastName" /><br />
				<a href="javascript:handleAddCustomer();" class="btn">Add Customer</a>
			</fieldset>
			<table class="customer-grid">
				<thead>
					<tr>
						<th>Last Name</th>
						<th>First Name</th>
					</tr>
					<tr>
						<td>Stark</td>
						<td>Ned</td>
					</tr>
					<tr>
						<td>Snow</td>
						<td>John</td>
					</tr>
				</thead>
			</table>
		</form>
		<script type="application/javascript" src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
		<script type="text/javascript">
			function handleAddCustomer() {
				var firstName = $("#firstName").val();
				var lastName = $("#lastName").val()
				$.ajax({
					type: "GET",
					url: "AddCustomerService.json",
					dataType:"json",
					data: { 
						firstName: firstName, 
						lastName: lastName
					},
					success:function(data) {
						if (data.status == "success") {
							$(".customer-grid").append('<tr><td>' + lastName + '</td><td>' + firstName + '</td></tr>');
						}
					}
				});
			}
		</script>
	</body>
</html>

Notice that the <form> element no longer has an action associated with it; now it’s just another container and is no longer used to submit the form to the server. Instead, the main submit button is now wired up to call a JavaScript function, named handleAddCustomer(). The job of this function is to trigger an Ajax request to submit the customer information to the server. There’s a bit more involved now because we can no longer take advantage of the <form> element’s ability to automatically create a network request. Breaking this down step-by-step:

var firstName = $("#firstName").val();
var lastName = $("#lastName").val()

Uses the jQuery library to retrieve what was entered in the first name and last name text fields

$.ajax({
	type: "GET",
	url: "AddCustomerService.json",
	dataType:"json",
	data: { 
		firstName: firstName, 
		lastName: lastName
	},
	success:function(data) {
		...
	}
});

Here we use jQuery’s ajax() helper function to set up and trigger the network call to add the customer name.

The type property in the ajax() call is either “GET” or “POST”, and determines how the information you are passing to the server is sent: either as GET, where values are encoded in the request URL itself (e.g. “AddCustomerService.json?firstName=Nathan&lastName=Derksen”) or as POST, where values are passed through one of the header fields that are sent to the server as part of the request. For local development using static sample data files GET is generally required, but for actual implementation this kind of a server call would usually use POST.

The url property sets the address of the service call you are making. For this example we are simulating the call using a static text file so the url points to the .json file in the same folder as the hosting Web page.

The dataType property allows us to work with JSON (JavaScript Object Notation) data, which gives us considerable flexibility in structuring the data that we want to submit and receive with the service call. The service can send data back using whatever JSON data structure we want. With a traditional page-driven application, response data is injected right into the HTML and once it’s there you can’t do much else without another server refresh. With JSON data, you can refer to the data elements using JavaScript for as long as you like without having to go back to the source. This is the key to full-screen applications, where we use JavaScript in the browser to do more of the layout and interaction and rely less on the server to structure the HTML.

The data property lets us pass information to the service request that pertains to the action to be performed. In this case, we are passing along the name of the customer to add to the database, but we can put whatever data we want here.

Lastly, the success property contains a function (called a callback function) that is invoked once the Ajax call has finished. It is passed a variable that contains the JSON data that the service call returned, and based on what data the service call returns, you can call the appropriate JavaScript, such as the following which checks to see if the service returned a status property with the value set to “success”.

if (data.status == "success") {
	$(".customer-grid").append('<tr><td>' + lastName + '</td><td>' + firstName + '</td></tr>');
}

Here the JavaScript is manipulating what’s shown on screen by changing the browser’s DOM (Document Object Model), which is the browser’s internal representation of everything that’s present in the browser window. The jQuery append() function here is used to dynamically append a row to the customer table containing the customer’s name once the service call has successfully completed.

Next Steps

I’ve shown here a very simple example just to compare the traditional page-driven application with the single-page application, there is obviously a lot more to it. In my next post I’ll be taking a look at the beginning of the process of creating a single-page application, starting from the design phase. Hope you’ll join me!