Fork me on GitHub

JavaScript, AJAX, JSON Tutorial

This tutorial looks at using JavaScript within WoOF templates and interacting with the WoOF server by AJAX (by both HTTP parameters and JSON).

To focus on JavaScript and AJAX, the below simple application will undertake adding or subtracting from a number. While this can be accomplished client-side with JavaScript, the tutorial demonstrates AJAX by sending the values to the WoOF server to undertake the calculations.

JavaScriptApp screen shot.

Download Tutorial Source

JavaScript

The below is the HTML and JavaScript for the page. While production applications should use a JavaScript framework (e.g. jQuery) to handle issues such as cross browser differences, the tutorial will use raw JavaScript to show it is JavaScript framework agnostic.

The reason that WoOF may use any JavaScript framework is that it does not interpret the web page contents. WoOF treats the content of a web page as text, providing only the necessary tag replacements. In the case below, WoOF provides the URLs for the AJAX calls. This means any JavaScript code (whether raw or part of a framework) may be included in the WoOF templates. It even means that WoOF templates can be used for other content types such as XML. The focus of this tutorial will be on including JavaScript within HTML web pages.

<html>

<head>
<script type="text/javascript">
	
	function addition() {
		var numberOne = document.getElementById("result").innerHTML;
		var numberTwo = document.getElementById("value").value;
		doAjax( { url: "#{addition}" 
				, payload: "numberOne=" + numberOne + "&numberTwo=" + numberTwo
				, handler: function(response) { document.getElementById("result").innerHTML = response; }
				}); 
	}

	function subtraction() {
		var numberOne = document.getElementById("result").innerHTML;
		var numberTwo = document.getElementById("value").value;
		doAjax( { url: "#{subtraction}"
				, payload: JSON.stringify({numberOne: numberOne, numberTwo: numberTwo})
				, handler: function(response) { 
						document.getElementById("result").innerHTML = JSON.parse(response).result; 
					}
				});
	}
	
	function doAjax( request ) {
		var ajax = new XMLHttpRequest();
		ajax.open("POST", request.url, false);
		ajax.onreadystatechange = function() {
			if (ajax.readyState == 4) {
				request.handler.call( request, ajax.responseText );
			}
		}
		ajax.send( request.payload );
	}
		
</script>
</head>

<body>

	<h1 id="result">1</h1>
	
	<p><input id="value" type="text" value="1" size="4" />
		<input type="button" value="add" onclick="addition()" />
		<input type="button" value="subtract" onclick="subtraction()" /></p>

</body>
</html>

Different payload types (HTTP parameters and JSON) are used for the respective AJAX requests. This is to demonstrate in the next sections how WoOF handles each payload type.

Including AJAX / JSON template extension

To include the AJAX / JSON template extension functionality, include the plug-in on the class path. For maven, it would be the following:

		<dependency>
			<groupId>net.officefloor.plugin</groupId>
			<artifactId>officeplugin_json</artifactId>
		</dependency>

WoOF will auto detect the extension and include it.

AJAX with HTTP parameters

The handling HTTP parameters in the AJAX request is very similar to handling HTML form submissions. The difference is that the default behaviour of re-rendering the template's content is to be avoided. To avoid re-rendering the template's content the below annotation is added to the servicing method to flag to not re-render the template.

public class TemplateLogic {

	@Data
	@HttpParameters
	public static class AdditionRequest implements Serializable {
		private String numberOne;
		private String numberTwo;
	}

	@NotRenderTemplateAfter
	public void addition(AdditionRequest request,
			ServerHttpConnection connection) throws IOException {

		// Add the numbers
		int result = Integer.parseInt(request.getNumberOne())
				+ Integer.parseInt(request.getNumberTwo());

		// Return the result
		connection.getHttpResponse().getEntityWriter()
				.write(String.valueOf(result));
	}

AJAX with JSON

To handle JSON content in both the request and response, the JSON content is mapped to Java Objects. The below demonstrates the:

  • annotation on the parameter class to have the injected object into the servicing method loaded with the JSON content from the HTTP request
  • JsonResponseWriter to write the JSON content to the HTTP response.

Note that there is no annotation on the servicing method to avoid re-rendering the template. WoOF identifies the method is servicing an AJAX request by the presence of a JsonResponseWriter parameter. WoOF will therefore not re-render the template and therefore only return the JSON content as the HTTP response entity.

	@Data
	@HttpJson
	public static class SubtractionRequest implements Serializable {
		private String numberOne;
		private String numberTwo;
	}

	@Data
	public static class JsonResponse {
		private final String result;
	}

	public void subtraction(SubtractionRequest request,
			JsonResponseWriter response) throws IOException {

		// Subtract the numbers
		int result = Integer.parseInt(request.getNumberOne())
				- Integer.parseInt(request.getNumberTwo());

		// Return the result
		response.writeResponse(new JsonResponse(String.valueOf(result)));
	}

}

The underlying implementation of JSON to Java Object mapping is via Jackson. Please see their documentation regarding additional annotations available to Java Objects to fine tune mapping of JSON to/from Java Objects.

Unit Test

The following unit tests manually undertake the AJAX calls to the WoOF server and verifying the correct responses.

	public void testHttpParameters() throws IOException {
		String response = this.doAjax("addition", "numberOne=2&numberTwo=1");
		assertEquals("Incorrect response", "3", response);
	}

	public void testHttpJson() throws IOException {
		String response = this.doAjax("subtraction",
				"{ \"numberOne\" : \"3\", \"numberTwo\" : \"1\" }");
		assertEquals("Incorrect response", "{\"result\":\"2\"}", response);
	}

	private String doAjax(String link, String payload) throws IOException {
		HttpPost post = new HttpPost("http://localhost:7878/template-" + link
				+ ".woof");
		post.setEntity(new StringEntity(payload));
		HttpResponse response = this.client.execute(post);
		assertEquals("Should be successful", 200, response.getStatusLine()
				.getStatusCode());
		return EntityUtils.toString(response.getEntity());
	}

Next

Please see the other tutorials for further features.