Sign In/My Account | View Cart  
advertisement


Listen Print Discuss

Using Ajax from Perl
by Dominic Mitchell | Pages: 1, 2, 3, 4

Enter CGI::Ajax

With a few small modifications, you can make the script use Ajax to check whether the username is valid. That way, any problems will show up immediately. There aren't many changes. At the top of the script, load the CGI::Ajax module and make a new object. At the same time, register the function check_username() as being callable via Ajax. After that, instead of calling main() directly, call build_html(), passing in a reference to main(). This is a very important part of how CGI::Ajax does its work. It gives CGI::Ajax the ability to intercept the regular flow of control when it needs to. You can also download the Ajax-enabled login code.

#!/usr/local/bin/perl
# User registration script.

use strict;
use warnings;

use CGI;
use CGI::Ajax;

my $cgi  = CGI->new();
my $ajax = CGI::Ajax->new( check_username => \&check_username );
print $ajax->build_html( $cgi, \&main );

The only other structural change is in the main() function. Instead of printing a header and the generated HTML, it now returns the content.

sub main {
    # ...
    # print $cgi->header();
    # print $html;
    return $html;
}

After doing that, CGI::Ajax will send the content to the browser for you.

With the server side of Ajax covered, it's time to look at the client side. The client needs to take advantage of the features that CGI::Ajax provides. To do this, you need a little bit of JavaScript. If you view the source of this second script, you'll see that CGI::Ajax has inserted some JavaScript at the end of the <head> section. This is the code that exposes your Perl functions to JavaScript. All that remains is to connect up events that occur in the page to those exposed Perl functions.

If you've used JavaScript before, you're probably thinking about an onchange attribute now. That's the right thought (to trigger the Ajax call when the username field changes), but it's not an ideal way of doing things, because it's intrusive. There's really no need for there to be JavaScript in the HTML at all. Instead, create a small file to bind the markup to the exposed Perl functions (download binding.js).

It starts off with the addLoadEvent function from Simon Willison. This function takes a piece of JavaScript and runs it when the page has finished loading. The useful bit is that you can call it more than once without ill effects. You could use the window.onload handler directly, but that would remove any previous code that had attached itself. By using addLoadEvent() everywhere, this ceases to be a problem.

// Run code when the page loads.
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      oldonload();
      func();
    }
  }
}

The next bit of JavaScript does the real work. Before doing anything, though, there is a small check to make sure that the browser is capable of handling all of this Ajax. By specifying the name of a browser function (document.getElementById) without the trailing parentheses, JavaScript returns a reference to it. If the function doesn't exist, it will return null instead. If that function doesn't exist, the code just returns straight away, resulting in no Ajax features on this page. This is graceful degradation, as it lets the ordinary page behavior occur if the enhanced behavior won't work.

When the code knows that it's safe to proceed, it queries the document for our username input element. If it finds it, the code arranges to call the check_username() function every time the username field changes. The two parameters are lists of IDs in the document. The first one is a list of parameters whose values to pass into check_username() on the server. The second list contains IDs where to insert the return values from the function.

// Set up functions to run when events occur.
function installHandlers() {
  if (!document.getElementById) return;
  var user = document.getElementById('user');
  if (user) {
      // When the user leaves this element, call the server.
      user.onchange = function() {
          check_username(['user'], ['baduser']);
      }
  }
}

With installHandlers() defined, all that remains is to ensure that it actually runs when the page loads.

addLoadEvent( installHandlers );

With binding.js completed, you need to make two small changes to the generated HTML. First, include a script tag to actually load it:

<script type="text/javascript" src="binding.js"></script>

Secondly, to create an element with an ID of baduser into which to insert the results. I created an empty emphasis tag just after the username field.

<p>Username: <input type="text" name="user" id="user"/>
<em id="baduser"></em></p>

With that in place, you should be able to register a username, and then watch it fail when you try to register it a second time. See how it's immediately noticeable that the username is invalid.

Pages: 1, 2, 3, 4

Next Pagearrow