An AJAX Example
To show an example of an AJAX application we will develop an AJAX
version of the likes application that has been used in previous
chapters. As a starting point we'll use the version that was developed
in the Web API chapter but modified so that it
will only serve an HTML page for the root URL (/
) - all other pages
return JSON responses. The database (model) part of the application is
the same; here is the controller part:
@app.route('/')
def index():
"""Home page"""
info = dict()
info['title'] = 'AJAX ListMaker!'
return template('jsonlikes.tpl', info)
@app.post('/likes')
def like(db):
"""Handle the /likes POST request from a JSON submission"""
if 'likes' in request.json:
likes = request.json['likes']
else:
likes = []
for like in likes:
if like != '':
store_like(db, like)
return "Success"
@app.get('/likes')
def getlikes(db):
"""Get a JSON version of the likes data"""
info = dict()
# get the list of likes from the database
info['likes'] = get_likes(db)
return info
@app.route('/static/')
def static(filename):
return static_file(filename=filename, root='static')
The application will accept a JSON POST submission to register one or
more new likes and will respond to a GET request on '/likes' with a JSON
list of likes. To build an AJAX application from this we need an HTML
page that makes appropriate AJAX calls. The original page will not
contain any data (the index
handler does not reference the database)
and so the first thing we will need to do is to retrieve the list of
likes and include them in the page. Here is the outline of a function
that creates a request object to query the /likes
URL:
function displayLikes() {
let httpRequest = makeRequest();
httpRequest.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
// process the response
}
}
}
httpRequest.open('GET', '/likes');
httpRequest.send(null);
}
The callback handler needs to take the JSON response and parse it to extract the list of likes. Recall that the JSON response will have the following form:
{
'likes': ['eggs', 'cheese', 'bread']
}
Our goal is to display this in the HTML page. If we assume that the page
has a <ul>
element with a known identifier then our handler just needs
to insert the list items into this element for display. So, in our
starter HTML page we will add:
<ul id='things'>
</ul>
We can now insert list items for each liked thing as follows:
let text = "";
let result = JSON.parse(this.responseText);
for(let i=0; i<result.likes.length; i++) {
text += "<li>" + result.likes[i] + "</li>";
}
document.getElementById('things').innerHTML = text;
This code constructs a string consisting of the list item elements and
inserts them as the innerHTML
property of the unordered list. This
replaces the previous contents of the list and so updates the display.
An alternative would be to use the DOM interface to create new elements
and contents but this code has the same effect and is simpler.
Having written this code we need to arrange for it to be called when the
page is loaded so that the initial list of items are displayed in the
page. To arrange for this we can use the window.onload
property which
should be set to a function that will be called when the page in the
current browser window has finished loading. In our case we want
displayLikes
to be called so we add the following inside the <head>
of the page:
<script language='javascript'>
window.onload = displayLikes;
</script>
Handling Updates
The next task is to handle new likes entered by the user. In the
original application these were handled by a simple form submission that
prompted a page reload. We want to use the same form but instead of
submitting it directly we will construct a JSON POST request instead. So
the form doesn't need a method
or action
attribute. We remove these
and add an id for the input element so that we can identify it from the
Javascript handler:
<form>
<legend>What do you like? </legend>
<ul>
<li><input id='likeinput' name='likes'></li>
</ul>
<button onclick='return formsubmit();'>Submit</button>
</form>
The submit button on the form has been replaced with a button
element
where we have set an onclick
handler that will call the function
formsubmit
when pressed. Note the technique here that the onclick
handler returns the value of the function. If the handler returns
false
then the form will not be submitted (recall that the default
action is to submit the form to the same URL as the page, so not setting
an action doesn't prevent submission).
The job of the formsubmit
handler is to take the text entered in the
input box, construct the right JSON data and send a POST request back to
the server. When the request returns, it should arrange to call the
displayLikes
function to update the display. Here's the implementation
of formsubmit
:
function formsubmit(){
let httpRequest = makeRequest();
httpRequest.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
displayLikes();
}
}
}
// set up the request parameters
httpRequest.open('POST', '/likes');
list = [document.getElementById('likeinput').value]
data = JSON.stringify({'likes': list});
httpRequest.setRequestHeader('Content-Type', 'application/json');
httpRequest.send(data);
// reset the form entry
document.getElementById('likeinput').value = "";
return false;
}
The first part of the function sets up the AJAX callback function which
just calls displayLikes
to update the page. The second part sets up
the rest of the request parameters. We construct the data to be sent by
first creating a list containing the value entered in the likeinput
entry in the form. We use JSON.stringify
to create a JSON string
representation of the object with a single likes
attribute. We then
set the content type of the request and send the request with the JSON
data as the payload.
The final step in the function is to reset the value in the form to the
empty string and return false
so that the form is not submitted.
We can put all of the Javascript code together in a single likes.js
file that is then loaded in the head of the HTML page.
<head>
<title>List Maker</title>
<script src='/static/likes.js'></script>
<script language='javascript'>
window.onload = displayLikes;
</script>
</head>
This is a relatively simple AJAX application. It illustrates the use of a single HTML page with no content that uses Javascript to make AJAX requests to update the page content and to submit requests to the server. The same architecture can be used for much more complex applications. Next time you visit Facebook or GMail, note how the initial page loaded is essentially empty and the content arrives after a bit of script activity. If you use your browser tools to observe the requests being made, you will see AJAX in action.