jQuery and Jython - Client-Server Web Apps with JavaScript and Java (2014)

Client-Server Web Apps with JavaScript and Java (2014)

Chapter 9. jQuery and Jython

Language is no longer regarded as peripheral to our grasp of the world we live in, but as central to it. Words are not mere vocal labels or communicational adjuncts superimposed upon an already given order of things. They are collective products of social interaction, essential instruments through which human beings constitute and articulate their world. This typically twentieth-century view of language has profoundly influenced developments throughout the whole range of human sciences.

—Roy Harris

Programming languages have an immediate and tangible impact on the lives of those who use them and on those who are not even aware of their existence. Amusingly enough, programmers often spend precious little time working with the fundamental features of a language. After gaining an understanding of these, they immediately look for ways to avoid reinventing the wheel. An abstraction level or generalization can become so popular that it becomes practically conflated with the original language.

The jQuery library is such a technology related to JavaScript. It has been widely adopted, and most JavaScript developers have used it extensively. Some consider it not just a library, but more of a internal Domain Specific Language (DSL). Thought of this way, jQuery is a small language with a focus on DOM manipulation, Ajax processing, and other common JavaScript tasks. In any case, jQuery use is so prevalent that you will find questions online of the form, “How to do X in JavaScript?” that are answered using jQuery idioms.

The abstraction layer that has made Java so successful is at a lower level than the language itself; it is the Java Virtual Machine (JVM) which processes the bytecode generated by the Java compiler. Java was intentionally designed from the onset with the JVM as an abstraction layer. Its independent existence has made it possible to create compilers for non-Java programming language implementations that target the JVM. The JVM is a well-engineered, highly optimized program and is the result of years of research and development. Developers who have no particular interest in the Java language can still benefit from this underlying technology.

The project created in this chapter will use jQuery and Jython (a JVM-based Python implementation) to demonstrate how simply a client-server web application can be prototyped.

Server Side: Jython

The Python programming language was initially released in the mid-1990’s by Guido van Rossum (its principal author and “Benevolent Dictator For Life”). Python is known for its clear, readable, and regular syntax. It departs from many of the idioms of C-based languages (like curly brackets). Because of its consistency and clarity, it has been adopted in many educational settings as the language taught in introductory programming classes. Python generally requires fewer lines of code than Java to perform a given task.

Jython is an implementation of Python that runs on the JVM. This allows for the creation of clear, concise Python programs that are run wherever Java is installed. Jython programs also can interact with Java objects, which introduces a range of possibilities for embedding Jython or using it in conjunction with native Java libraries.

Python Web Server

As a scripting language, Python also can be used in ways unfamiliar to Java developers. For instance, to run a static web server that serves files from an arbitrary directory without writing an original line of code, you can simply navigate to the directory in question and invoke the following:

python -m SimpleHTTPServer

Jython Web Server

Creating a Python-based web server using the SimpleHTTPServer referenced above requires only a few lines of code:

import SimpleHTTPServer

import SocketServer

import os

os.chdir('src/main/resources')

httpd = SocketServer.TCPServer(("", 8000),

SimpleHTTPServer.SimpleHTTPRequestHandler)

print "serving at port 8000"

httpd.serve_forever()

Jython can be invoked from the command line or embedded inside of a Java application. For example, this script can be called from inside of a Java class:

package com.oreilly.jython;

import java.io.File;

import java.io.IOException;

import org.python.util.PythonInterpreter;

import org.apache.commons.io.FileUtils;

public class Server

{

public static void main( String[] args ) throws IOException

{

new PythonInterpreter().exec(

FileUtils.readFileToString(

new File("python/http_server.py")

)

);

}

}

The project, including its dependencies, is available on GitHub. It can be built using mvn clean install and run by calling mvn exec:java.

Mock APIs

A static web server has significant limitations. Most notably for a web app developer, it cannot produce dynamic content. However, it is possible to mock out APIs by simply creating files that contain representative data. For example, a directory named api with a file called groups.json can be created and would be available from the http://localhost:8000/api/groups.json URL. The content of this JSON file is an array of groups, each of which is an object that has a name, description, and URL:

[

{

"name":"duckduckgo",

"description":"Internet search engine founded by Gabriel Weinberg",

"url":"http://duckduckgo.com/"

},

{

"name":"angular",

"description":"Open source JavaScript framework initially created" +

" by Adam Abrons and Miško Hevery",

"url":"http://angularjs.org/"

},

{

"name":"twitter",

"description":"Online social networking service and microblogging" +

" service created by Jack Dorsey",

"url":"http://twitter.com/"

},

{

"name":"netflix",

"description":"American provider of on-demand Internet streaming "+

"media Marc Randolph and Reed Hastings",

"url":"http://netflix.com/"

}

]

Directories relative to the root directory are reflected in the URL path, and many web servers will respond with the desired content type if a corresponding extension is specified. Client-side developers can work in parallel using a mock API like this while server-side configuration and development proceeds.

Client Side: jQuery

Since its release in 2006, jQuery has simplified cross-browser development in several different ways. It was created by John Resig with the intention of changing the way that developers write JavaScript. Specifically, it sought to remove common repetitive tasks and replace obscure, verbose JavaScript with a clear, succinct syntax.

When encountering jQuery for the first time, the number of dollar signs that appear in code can be surprising. This is because $ represents the jQuery object in the namespace for the library. So the following are equivalent:

jQuery('a')

$('a')

Running JavaScript after a page loads is accomplished in standard JavaScript using the body onload event. The load event occurs after a page is fully rendered (including all assets such as images). jQuery provides an event that runs slightly earlier, after the DOM is ready. There are several different syntaxes to specify this handler. The recommended one is the verbose version:

$(document).ready(function() {

// Handler for .ready() called.

});

which is equivalent to:

$(function() {

// Handler for .ready() called.

});

In general, the pattern of jQuery usage involves finding DOM elements and then doing something with them. Finding DOM elements is accomplished using a string pattern of some sort (CSS Selectors or XPath). Doing something might be as straightforward as reading the contents of the element, or could involve its contents or style or associating a behavior with it through an event handler. jQuery also provides a consistent interface for Ajax processing. It is also designed to be extended using plug-ins.

DOM Traversal and Manipulation

Much of the criticism leveled at JavaScript is due to difficulties in interacting with the browser DOM. jQuery eases interaction between HTML and JavaScript by providing an elegant interface for DOM selection, traversal, and manipulation. This is most frequently accomplished using CSS selectors from CSS 1-3, as well as some specific to jQuery. CSS selectors are strings containing patterns that can simply refer to an element by name or specify a complex series of matching conditions. If all conditions specified by a pattern are true for a given element, the selector matches it.Table 9-1 gives some jQuery examples.

Table 9-1. jQuery examples

Selector

Description

$('$div')

All divs

$('#myElement')

Elements with an ID of myElement

$('.myClass')

All elements with a class of myClass

$('div#myDiv')

All divs with an ID of myDiv

$('ul.myListClass li')

All list items inside of a ul with an class of myListClass

$('ul.projects li:first')

The first list item in uls with a class of projects

As shown in Table 9-2, other attributes can also be accessed, even if only part of the value searched for is known.

Table 9-2. jQuery partial values

Selector

Description

$('input[name*="formInput"]')

Input elements with a name with a substring of formInput

$('input[name^="formInput"]')

Input elements with a name that starts with formInput

Characters with special meanings must be escaped using two backslashes. For example, if you had an input text field with an ID of myForm:username, the following selector could be used to identify the element:

$('input#myForm\\:username')

CSS selectors are very expressive, but at times result in an array of objects that need to be further processed. Many jQuery methods return a jQuery object that you can then use to call another method. So for instance, a subtree of the DOM can be searched to find a specific element:

$('div.projects').find('.project1')

Utility Functions

jQuery also provides a number of utility functions that can handle similar tasks on collections of elements, as shown in Table 9-3. Libraries like underscore.js overlap somewhat with jQuery but provide even more capabilities for manipulating lists and objects. The JavaScript language has been augmented over time to include similar methods. jQuery’s methods will likely continue to be used for the near future due to the benefit of compatibility with legacy browsers.

Table 9-3. Utility functions

jQuery

Underscore

JavaScript 1.6

iteration

each

each

forEach

transform

map

map

map

filtering

grep

filter, where

find index

inArray

indexOf, lastIndexOf

After an object has been located, it is trivial to do something with it. Function chaining makes manipulating elements especially convenient:

$('div.items').find('.item1').text('Hi World').css('background-color', 'blue')

The modification of specific elements in the DOM leads into the development of dynamic interactive user interfaces that respond to a user’s actions.

The pattern of “find an element” and “do something with it” is simple, powerful, and immediate. To appreciate this, simply pop open a browser web console on a page that includes jQuery and begin writing some selectors that return objects. When you have located some, try changing their text or styling. If you want to try this pattern on a page that does not include jQuery, you can load it by running a few simple commands in advance:

var script= document.createElement('script');

script.type= 'text/javascript';

script.src= 'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js';

document.head.appendChild(script);

Effects

jQuery includes convenient methods for modifying CSS to show or hide elements. It also includes methods related to animation, including fading and sliding effects:

$('form#myForm').hide()

$('form#myForm').show()

$('form#myForm').slideUp('slow')

$('form#myForm').slideDown('slow')

$('form#myForm').fadeIn('slow')

$('form#myForm').fadeOut('slow')

Event Handling

jQuery selectors can be used to attach event handlers to specific elements. The actual syntax used to this end has varied a bit over time. Methods such as bind, live, and delegate have been superseded by on and off. One challenge introduced with increasingly dynamic interfaces is that you might want to define an event handler for an element that could come into existence at some later point depending on user interaction. The solution to this challenge using jQuery is to bind the event at a higher level of the DOM. When the event is fired, even though the event is not directly associated with the element, it will be propagated up and handled when the selector is matched:

$(document).on('click','.myClass', function(){

console.log('Hey you clicked me.');

});

Ajax

jQuery wraps the XMLHttpRequest browser object into a more usable, simple form that behaves in a consistent manner across browsers. jQuery.ajax is a general Ajax requester, and more specific functions provide a shorthand for commonly used HTTP GET or POST commands. Because of the popularity of JSON communication in Ajax applications, it includes a getJSON method as well and also provides the ability to make calls using JSONP.

jQuery is an amazing but relatively simple library. The concepts introduced in this chapter cover the bulk of what it is designed for at a high level. Books like Cody Lindley’s jQuery Cookbook (O’Reilly) are very helpful in showing how the library can be used for specific tasks.

jQuery and Higher-Level Abstractions

jQuery greatly simplified cross-browser development and made it possible to develop a class of web applications with significant Ajax interactions, event handling, and DOM manipulation much more easily. Its popularity suggests that it will continue to be influential and popular for many years. But as web apps have grown in size, new approaches have emerged to tame the complexity. Larger-scale design patterns (MVC) and programming paradigms (functional programming) provide alternatives and compliments to the functionality available in jQuery.

Consider, for example, the simple practice of assigning variables. This basic task becomes burdensome as the number of variables in a program (with dependencies on one another) begins to grow. Object-oriented programming was popularized with the notion that an object could encapsulate a group of variables that represent the state of an object. The object would be given defined methods to allow access to and manipulation of an object’s state.

Object orientation (in the classical sense) is not particularly influential in the JavaScript community, but other solutions address the challenge of keeping variables in sync. These include two-way data binding between model and view components (AngularJS) and Functional Reactive Programming, which defines data types that represent a value over time (rather than being concerned only about a variable’s value at a particular instant).

FUNCTIONAL REACTIVE PROGRAMMING

Functional Reactive Programming (FRP) is a declarative approach to GUI design that has been garnering recent attention. Its selling point is that many of the constructs addressed directly by jQuery (event handlers, callbacks, and DOM manipulations) are not done directly.

jQuery has its limitations, and separate projects have sprung up to provide niceties like client-side templates, modularization of code, and management of callbacks. Others seek to simplify the complexities of direct DOM manipulation. Many of these can be used in conjunction with jQuery, and jQuery’s success in taming browser incompatibilities and providing a consistent interface for DOM manipulation have made it an established presence in JavaScript development.

Project

The Jython-based HTTP server introduced earlier in this chapter simply responds to requests for files in the specified directory. This is sufficient to serve up HTML and JavaScript files. Although the server itself provides little functionality, there are ways to effectively expand the server tier by making external calls to third-party APIs. One API that is publicly available and requires no special setup or API keys is the GitHub API. The application described will do anything from lookups on GitHub data to listing members of select GitHub Groups (as shown in Figure 9-1).

GitHub Groups

Figure 9-1. GitHub Groups

Basic HTML

The application can be “built out” from scratch starting with a simple HTML file with a bit of embedded CSS. Although stylesheets are better externalized for production projects (consistent with the previous discussion related to Unobtrusive JavaScript), it is simpler to keep all the code in view when developing in this manner:

<html>

<head>

<title>index</title>

<style type="text/css" media="screen">

img {width: 50; height: 50;}

span {padding: 7px;}

</style>

</head>

<body>

<select id="selected_group">

<option>Select Group</option>

</select>

<div id="images"></div>

</body>

</html>

JavaScript and jQuery

Underneath the closing style element, add a reference to jQuery, which is available from Google:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js">

</script>

The options that will appear in the dropdown will be loaded in a JSON file listed earlier.

The jQuery code to load this JSON file calls $.getJSON and iterates through each record returned and appends the option to the select element. When an option is actually selected, a function called getGroup is called:

<script>

$.getJSON("/api/groups.json",

function(data) {

$.each(data, function(i,item){

$("<option>"+item.name+"</option>").

appendTo("#selected_group");

});

}).error(function(){ console.log("error");});

$(document).ready(function() {

$('#selected_group').bind('change',

function (){

getGroup();

});

});

</script>

The getGroup() function clears any previous display, then makes a call to GitHub to retrieve the data for the selected group. The names and avatars for each group member are then displayed:

function getGroup(){

$("#images").empty();

$.getJSON("https://api.github.com/orgs/"+

$('#selected_group').val()+"/members",

function(data) {

$.each(data,

function(i,item){

$("<span>" +

item.login +

"</span><img/>").

attr("src", item.avatar_url).

appendTo("#images");

});

}).error(function(){ console.log("error"); });

}

This example shows how straightforward it is to use jQuery to make local or remote web API calls and display the results. The entire client side consists of fewer than 40 lines of HTML, CSS, and JavaScript. Add to this cross-browser support afforded by jQuery and it is apparent why it was so quickly and widely adopted.

That said, the project does leave something to be desired. It’s not exactly pretty or terribly responsive to different devices. The strings containing snippets containing HTML might also make you cringe and wish for a templating solution of some sort. You might also feel that the nested function calls are a bit foreign and that there might be a way of providing a more natural functional syntax to the calls. You are not alone in having this reaction. The JavaScript world has developed projects and libraries that will be discussed in later chapters.

Conclusion

A client-server approach to web development requires only a few minutes of initial setup. The server project contained in this chapter simply serves static assets. Static HTML files and mocked-out API calls stored in JSON files can be created on the file system and require no build to update. Once in place, jQuery can be used to make local or remote API calls and display the resulting data. A project of this nature does not require a deep dive into Java or Python, and even simplifies the amount of JavaScript that must be mastered. The result is a simple dynamic web application that can be viewed in a variety of browsers.