Irrational Exuberance!

Using Ajax with the BeepBeep Microframework

July 6, 2009. Filed under jqueryerlangbeepbeep

Building on the extremely basic introduction to BeepBeep, in this second article in the Intro to BeepBeep series we'll take a look at using Ajax with BeepBeep.

Like most simple Ajax examples, this one will be rather contrived, but nonetheless should demonstrate the concept. I won't try to convince the dear reader that the example isn't exceptionally uninspired, we will simply poll the BeepBeep application for the current time and then display it to the user1.

BeepBeep Setup

(If you haven't installed BeepBeep, please refer to the previous Getting Started with BeepBeep tutorial before going further.)

  1. Use BeepBeep to start our new project.

    cd ~/git/beepbeep/
    script/new_beep.erl BB_Time ../BB_Time
    
  2. Then navigate to the project's directory.

    cd ~/git/BB_Time/bb_time
    

With that, the project is initialized and ready for our special sauce.

BeepBeep Logic

Next, we need to setup the BeepBeep portion of the application (as opposed to the JavaScript portion, which we'll configure last).

  1. First we need to create two controllers:

    • a controller to display the initial page
    • a controller that will be polled for the current time.

    Open up src/home_controller.erl, and replace the existing handle_request handler (for both index and shows) with this code:

    handle_request("index",[]) ->
        {_A,B,_C} = erlang:now(),
        {render,"home/index.html",[{time, B}]};
    
    handle_request("time",[]) ->
        {_A,B,_C} = erlang:now(),
        {render,"home/ajax.html",[{time, B}]}.
    

    The two handles look nearly identical except for rendering different views, which makes a lot of sense, because from the server's perspective Ajax requests are no different than a normal HTTP request.

    Also, replace the existing before_filter implementation with:

    before_filter() ->
        ok.
    

    Then save and close home_controller.erl.

  2. Next we need to edit the base view. Open up views/base.html and change it to:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
           "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
      <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
      <title>Welcome to BeepBeep Ajax</title>
      <link href="/stylesheets/style.css" rel="stylesheet" type="text/css"/>
      <script type="text/javascript" 
      src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
      </script>
      <script type="text/javascript" src="/js/time.js"></script>
    </head>
      <body>
        {% block content %}{% endblock %}
      </body>
    </html>
    

    The signifigant changes are adding the JavaScript import for the non-existant js/time.js file (we'll put it together later), and adding the Google hosted jQuery library.

  3. Third, create the views/home/ajax.html template, which should look like this:

    <p> Time is {{ time }}</p>
    

    Note that we don't start it with a {% extends "../base.html" %} block, as we will be injecting this HTML fragment into an existing HTML page.

  4. Next edit the views/home/index.html template to look like:

    {% extends "../base.html" %}
    {% block content %}
        <div id="time">
          {% include "ajax.html" %}
        </div>
    {% endblock %}
    

    If you're not familar with Django, you may not have encountered the include tag, which injects the contents of another file into the current file, and will evaluate the injected template using the injecting template's context.

    Note that this also reveals one of the awkward aspects of ErlyDTL, which is that it doesn't understand paths as originating in the views/ folder, but instead requires them to be relative to the current template. That is to say, that home/index.html must write the relative path to ../base.html, and also that the include tag in index.html must refer to ajax.html, rather than home/ajax.html. This is a bit of a deviation from expected Django behavior, so be careful.

  5. Finally let's verify that our little app works.

    make
    ./start-server.sh
    

    Then go to the http://localhost:8000/ and the http://localhost:8000/ajax pages to see they are rendering the correct pages.

With that, we're quite close to completing our simple Ajax app, missing only the Ajax.

JavaScript Logic

We're already including jQuery into base.html , we just need to create and flesh out js/time.js a bit.

mkdir www/js
emacs www/js/time.js

Then add this code:

var update = function() {
    $("#time").load("/home/time");
}
setInterval(update, 1000);

Finally, reload http://localhost:8000/ and you'll see yet another egregious violation of Ajax occuring right before your eyes and powered by BeepBeep!

(You can grab the code for this tutorial at BB_Time in the BeeBeep Examples repository.)

In the next segment of this tutorial we'll take a look at using BeepBeep along with a persistent data store to bring together the bare minimum components for providing a real service instead of a tinkertoy.


  1. Of course it would be simpler to just use client side JavaScript for the entire ordeal, but... I'm just trying to demonstrate a concept.