Beefy Boxes and Bandwidth Generously Provided by pair Networks httptech
XP is just a number
 
PerlMonks  

CGI/Ajax example: lookup a value when a field is filled in

by Your Mother (Canon)
on Dec 06, 2008 at 02:24 UTC ( #728467=note: print w/ replies, xml ) Need Help??


in reply to CGI how to lookup a value when a Field is filled in

Here you go. It's minimal/simplistic but it's functional and self-contained. You should be able to walk through it and see how things are working. I doubt this thread will expand so I'm going to forgo the readmore tags.

use strict; use warnings; use CGI qw(:standard); use Template; use JSON::XS; # Don't use CGI::Carp in production, it's here to make your life # easier while you experiment with this. use CGI::Carp qw(fatalsToBrowser); my $default = "splash"; my %actions = ( $default => \&show_form, ajax_lookup => \&ajax_lookup, ); my $action = param("x") || $default; my $executable = $actions{$action} || \&no_such_action; $executable->(); # Subroutines #--------------------------------------------------------------------- sub show_form { print header(); my $tt2 = Template->new(); $tt2->process(\*DATA, { self_uri => CGI::url(), usernames => [ map { $_->{username} } @{_du +mmy_db()} ], }) or die $tt2->error; } sub ajax_lookup { my $data = _dummy_db(); my $query = param("username"); my $result = {}; for my $row ( @{$data} ) { $result = $row if lc($query) eq lc($row->{username}); } print header("application/json"), encode_json($result); } sub no_such_action { print header(), h1("Nopers! Don't know how to do that!"); } sub _dummy_db { return [ { username => "paco", fish => "Sunfish", }, { username => "YourUncle", fish => "Coelacanth", }, { username => "hiragana", fish => "Monkfish", }, { username => "MosaicNL", fish => "Sixgill Shark", }, ]; } __DATA__ <?xml version="1.0" encoding="UTF-8"?> <!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" lang="en-US" xml:lang="en-US"> <head> <title>OH, HAI! I CAN HAS AJAKS?</title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.js"></s +cript> <script type="text/javascript">//<![CDATA[ $(function() { $("input[name='username']").bind("keyup", function(){ var myField = $(this); var myData = { username: myFiel +d.val() ,x: "ajax_lookup" }; $.ajax({ type: "GET" ,dataType: "json" ,url: "[% self_uri %]" ,data: myData ,success: function(json){ if ( json.username ) { $("input[name='fish'] +").val(json.fish); } else { $("input[name='fish'] +").val(""); } } }); }); }); //]]> </script> </head> <body> <form action="[% self_uri %]" method="post"> <fieldset> <legend>Simplistic Ajax Example</legend> <p> <label for="username">Username</label> <input id="username" type=" +text" name="username"/> <label for="fish">Fish</label> <input id="fish" type="text" name=" +fish"/> </p> <p style="clear:both; font-size:9px"> Usernames you can search for: <i>[% usernames.join(", ") %]</i> +. </p> </fieldset> </form> </body> </html>

There are some Perl idioms in there to make the thing terse enough for a small sample. So, just to explain: the __DATA__ section is a Template Toolkit template. Check the docs if it doesn't make sense.

The CGI proper does exactly three things; all different. If called without args, or with x=show_form, it prints the template which has a form in it. It sends two pieces of data to the template: self_uri (its own URI for the Ajax call to use) and usernames (an array ref from our "DB" of users to help prompt the person testing the form).

Instead of names and addresses, I've given each username a fish. When the page loads, the jQuery installs a keyup listener on the username field: $("input[name='username']").bind("keyup", function()...). You can read up on how jQuery selectors work. It's easy and intuitive. It's just CSS for the most part.

The next part is the Ajax. Ajax traditionally used XML, hence the "X." But I find JSON as a data layer superior in almost all cases. JSON::XS is perhaps the fastest data serializing available from Perl. So, read some of this page, jQuery/Ajax, to see what's going on. It should be pretty obvious.

Our Ajax call will GET data of the type json from the same URL the CGI displays the form with the arguments x=ajax_lookup (which sub to run in the CGI) and username=[whatever the value of the username field is on the last keyup].

The CGI then uses the username to look in the "DB" and returns a JSON data object like { username: "found user", fish: "Fish type" } if a username matches or {} if none does. The results get sent to the success: function(json){...} which is installed into our Ajax call. If the JSON data has a username, then its "fish" is put into the other form field. If not, the field is emptied. Ta!

The third handler, no_such_action, is just there for code "completeness." Arbitrary user input should never be able to break an application.

If this were a real application I'd install an "intent" layer in the keyup binding. You probably don't want to lookup the users on every keystroke. Just the one which is followed by a brief pause, probably, meaning the user is done typing (similar to hover intent stuff for mouseovers on menus so they don't flicker on and off but allow for friendlier UI). There are jQuery plugins for this -- I used one a year ago and can't remember its name.

As you can see, it's quite easy, just confusing until you know how it all hangs together. Something like Catalyst underneath it makes it easy to extend it all over the place. Hope that helps get you (and anyone else) going. :)


Comment on CGI/Ajax example: lookup a value when a field is filled in
Select or Download Code

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://728467]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (11)
As of 2014-04-17 08:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (441 votes), past polls