Skip to main content

skip to main content

developerWorks  >  XML | Web development  >

Ajax and XML: Ajax for forms

Use Ajax techniques to create input forms

developerWorks
Document options

Document options requiring JavaScript are not displayed

Discuss

Sample code


Rate this page

Help us improve this content


Level: Intermediate

Jack D Herrington (jherr@pobox.com), Senior Software Engineer, Leverage Software Inc.

22 Jan 2008

Augmenting your HTML forms with Asynchronous JavaScript™ + XML (Ajax) callbacks to the server is a practical way to add Web 2.0 functionality to your application. Discover a variety of techniques to add Ajax code and enhance the user experience for PHP applications.

When you think about Web 2.0 applications, often the most glamorous of them come to mind: the video of YouTube, the über-cool scrolling map of Google Maps, the geo-location functionality in Flikr. Often overlooked in such sites, however, is the humble HTML form that has undergone a big transformation with the popularization of Ajax technology.

In this article, I show you how to use the Prototype.js JavaScript library to solve common user experience problems as you augment forms with Ajax code.

Simple Ajax form submission

Start with something really simple: a multi-field registration form that you want to submit with Ajax instead of using the regular Web form posting path. This simple forms page is shown in Listing 1.


Listing 1. index.html
                
<html>
<head>
<script src="prototype.js"></script>
</head>
<body>
<form id="myform">
<table>
  <tr><td>First</td><td><input type="text" name="first"></td></tr>
  <tr><td>Last</td><td><input type="text" name="last"></td></tr>
  <tr><td>Email</td><td><input type="text" name="email"></td></tr>
</table>
<input type="button" onclick="dosubmit()" value="Submit">
</form>
<div id="result" style="padding:5px;">
</div>
<script>
function dosubmit( ) {
  new Ajax.Updater( 'result', 'add.php', { method: 'post',
    parameters: $('myform').serialize() } );
  $('myform').reset();
}
</script>
</body>
</html>

At the top of the file, I include the prototype.js JavaScript file, which will do all the Ajax work for me. After that is a traditional HTML form with three fields: first, last, and email. Below that is the button that submits the form using the dosubmit() JavaScript function.

This dosubmit() function uses the Ajax.Updater class to post the data to the add.php script. Then, you add options to the call. In this case, I set the method of submission to post and add the parameters from the form by using the serialize() method on the form. This serialize() method is not standard JavaScript code: The JavaScript library provides it.

The first item in the call to Ajax.Updater is the ID of the <div> tag, which receives the HTML that the add.php script returns. It's the easiest way to get notification back to the user about what happened when he or she clicked the button.

The add.php script is shown in Listing 2.


Listing 2. add.php
                
Thanks <?php echo( $_POST['first'] ) ?> <?php echo( $_POST['last'] ) ?>!

All it does is echo back what was posted from the form. In reality, this would likely add a record to a database, but you can handle that kind of business logic work for yourself.

When I first load the form, I see something like Figure 1 in my browser.


Figure 1. A simple Ajax form
A simple Ajax form

I then click Submit, which sends the form data to the page, and I get the returned HTML from the add.php page right below the Submit button, as shown in Figure 2.


Figure 2. The response following the submission
The response following the submission

Another variation on forms with Ajax is the auto-fillin form, which updates field values depending on the value of some key fields—for example, typing a customer's ID, clicking a button, and then getting the current customer records in the other fields.

This type of auto-fillin form is shown in Listing 3.


Listing 3. index.html
                
<html>
<head>
<script src="prototype.js"></script>
</head>
<body>
<form id="myform">
<table>
  <tr><td>ID</td><td><input 
    type="text" name="id"></td></tr>
  <tr><td>First</td><td><input type="text" 
    name="first" id="elFirst"></td></tr>
  <tr><td>Last</td><td><input type="text" 
    name="last" id="elLast"></td></tr>
  <tr><td>Email</td><td><input type="text" 
    name="email" id="elEmail"></td></tr>
</table>
<input type="button" onclick="dofill()" value="Fill Fields">
</form>
<script>
function dofill( ) {
  new Ajax.Updater( 'result', 'getdata.php', 
    { method: 'post', parameters: $('myform').serialize(),
  onSuccess: function( transport ) {
    $('elFirst').value = transport.responseXML.getElementsByTagName('first')
      [0].firstChild.nodeValue;
    $('elLast').value = transport.responseXML.getElementsByTagName('last')
      [0].firstChild.nodeValue;
    $('elEmail').value = transport.responseXML.getElementsByTagName('email')
      [0].firstChild.nodeValue;
  } } );
}
</script>
</body>
</html>

I've added a new field to the original form from Listing 1 called ID. That's where you put in the customer's ID. Then, the new dofill() function calls the getdata.php page, which returns XML code that has the first name, last name, and e-mail address for the given customer ID.

The onSuccess handler that I send to the Ajax.Updater call uses the native Document Object Model (DOM) functions available in all browsers to crack the downloaded XML data. It then sets the value of the elFirst, elLast, and elEmail <input> items to the values returned in the XML.

The getdata.php page is shown in Listing 4.


Listing 4. getdata.php
                
<?php
header( "content-type: text/xml" );

$first = ' ';
$last = ' ';
$email = ' ';

if ( $_POST['id'] == '1' )
{
  $first = 'Jack';
  $last = 'Herrington';
  $email = 'jherr@pobox.com';
}
?>
<data>
<first><?php echo( $first ) ?></first>
<last><?php echo( $last ) ?></last>
<email><?php echo( $email ) ?></email>
</data>

It's really just a stub method of code that normally calls the database to get the first name, last name, and e-mail address of the given record.

When I first bring up the page, I see something like Figure 3.


Figure 3. A fill-in form
Fill-in form

I then type 1 in the ID field and click Fill Fields, which goes off to the getdata.php page to get the first name, last name, and e-mail address and update the corresponding fields. This is shown in Figure 4.


Figure 4. The script fills in the fields based on the ID
The script fills in the fields based       on the ID

For my next Ajax slight-of-hand, I create an update in-place to-do list.



Back to top


Lists that update in-place

One of the common demos for Ruby on Rails is the to-do list, which updates in-place. That means that the list of items is at the top of the page, and there is a text box below the list. When I type something into the text box and click Submit, the list at the top of the page updates with the new item without changing the page. And the text box in which I typed the text resets so that I can keep adding stuff with little effort.

It's actually a terribly difficult trick, so I figured I show off how to do it in PHP. The page for the to-do list is shown in Listing 5.


Listing 5. index.php
                
<html>
<head>
<script src="prototype.js"></script>
</head>
<body>

<div id="result" style="padding:5px;">
<?php
$fh = fopen( 'list.txt', 'r' );
while( $str = fgets( $fh ) ) {
?>
<?php echo( $str ); ?><br/>
<?php
}
?>
</div>

<form id="myform">
<input type="text" name="todo">
</form>

<input type="button" onclick="dosubmit()" value="Submit">

<script>
function dosubmit( ) {
  new Ajax.Updater( 'result', 'add.php',
    { method: 'post', parameters: $('myform').serialize() } );
  $('myform').reset();
}
</script>

</body>
</html>

Instead of holding the to-do list in a database, I just use a flat text file called list.txt to store the items one per line. So, to put the list on the top of the page, I simply open the file and read each line in to the <div> tag with the ID of result.

Below that is the form with the text input for the to-do item. And below that is the button that calls the dosubmit() JavaScript function. That JavaScript function uses the Ajax.Updater class to call the add.php page, which adds the item and returns the new list with the item appended to it.

This add.php script is shown in Listing 6.


Listing 6. add.php
                
<?php
$total = '';

$fh = fopen( 'list.txt', 'r' );
while( $str = fgets( $fh ) ) {
?>
<?php echo( $str ); ?><br/>
<?php
  $total .= $str;
}

if ( array_key_exists( 'todo', $_POST ) )
{
?>
<?php echo( $_POST['todo'] ); ?><br/>
<?php
  $fh = fopen( 'list.txt', 'w' );
  fwrite( $fh, $total."\n".$_POST['todo'] );
  fclose( $fh );
}
?>

My silly list of to-do items is shown in Listing 7.


Listing 7. list.txt
                
Get swim goggles
Practice swimming
Swim in race

When I first go to the page, I see something like Figure 5.


Figure 5. Preparing to add a to-do item
Preparing to add a to-do item

I type Finish in record time, and then click Submit. Then, without a page refresh, I see the result shown in Figure 6.


Figure 6. The page after inserting a record
The page after inserting a record

Of course, this isn't the only cool thing in the Rails demo of a to-do list. But it's one part of the Web 2.0 "wow" factor. Actually, if you haven't tried Rails, I strongly recommend it for any Web engineer. Even if you don't use it in your own projects, it's really interesting to see how applications are organized, how the model-view-controller (MVC) mechanism is used, and how easy the database persistence model is.

Another common Web requirement is the expanding list of fields. I call these expando lists.



Back to top


Expando lists

What happens when you can have an unlimited number of keywords associated with a record? Well, one way to handle it is to use commas to separate the keywords. Another way is to have a button that adds new keyword fields on the fly to allow users to add as many keywords as they want. I use the second approach in Listing 8.


Listing 8. index.html
                
<html>
<head>
<script src="prototype.js"></script>
</head>
<body>
<form id="myform">
<table id="keytable">
  <tr><td>Keyword</td><td><input type="text" 
    name="keyword_1"></td></tr>
</table>
</form>

<input type="button" onclick="addkeyword()" value="Add Keyword">
<input type="button" onclick="dosubmit()" value="Submit">

<div id="result" style="padding:5px;">
</div>

<script>
var nextkeyid = 2;
function addkeyword()
{
  var elTR = $('keytable').insertRow( -1 );

  var elTitleTD = elTR.insertCell( -1 );
  elTitleTD.appendChild( document.createTextNode( 'Keyword' ) );

  var elInput = document.createElement( 'input' );
  elInput.type = 'text';
  elInput.name = 'keyword_'+nextkeyid;
  nextkeyid++;

  var elInputTD = elTR.insertCell( -1 );
  elInputTD.appendChild( elInput );
}
function dosubmit( ) {
  new Ajax.Updater( 'result', 'add.php', 
    { method: 'post', parameters: $('myform').serialize() } );
}
</script>
</body>
</html>

The real trick here is in the addkeyword() function, which uses insertRow and insertCell to create a new row in the table of keywords. Then, it uses document.createElement to create a new input field to hold the keyword. The Ajax.Updater code, which is called when users click Submit, calls the add.php script. This add.php script simply returns the list of keywords that the form gives it. This script is shown in Listing 9.


Listing 9. add.php
                
Post Result:<br/>
<?php var_export( $_POST ) ?>

When I bring up the page in my browser, I first see something like Figure 7.


Figure 7. The keyword form with a single keyword
The keyword form with a single keyword

I click Add Keyword a few times to add new fields, then click Submit. I get the screen shown in Figure 8.


Figure 8. The keyword form after adding keywords and clicking Submit
The keyword form after adding keywords and clicking Submit

This is an ideal way to allow users to add multiple values associated with a single record for things like phone numbers, keywords, and addresses. Another common use of Ajax is to implement login forms.



Back to top


Login forms

Login forms in Ajax are particularly cool, because they can give you instant feedback on whether you were able to log in and also because they can perform in-place logins. Imagine that you're looking at an article on which you want to comment, but you aren't logged in. With Ajax, you could log in while you're still looking at the article. If your credentials are accepted, a new form appears that you can use to add a comment. This process is much easier than having to track which article a person was looking at through the login flow to redirect the person after a successful login.

My simple version of the Ajax login is shown in Listing 10.


Listing 10. index.html
                
<html>
<head>
<script src="prototype.js"></script>
</head>
<body>
<form id="logform">
User: <input type="text" name="user"><br/>
Password: <input type="password" name="password"><br/>
<input type="button" onclick="login()" value="Login">
</form>
<div id="noway" style="display:none;">
  No way!
</div>
<script>
function login() {
  new Ajax.Request( 'login.php',
  {
    method: 'post',
    postBody: $('logform').serialize(),
    onSuccess: function( transport ) {
      if( transport.responseText.match( /\<ok\/\>/ ) )
        window.location = 'home.html';
      else
        $('noway').style.display='block';
    }
  } );
}
</script>
</body>
</html>

The User and Password fields are in the form at the top of the file. Below those is a <div> tag with the ID noway, which will be shown if the login is not accepted. The login() JavaScript method makes the login attempt using the Ajax.Request class. If the returned XML from login.php is <ok />, the form redirects the user to the home page. Otherwise, it brings up the noway text.

The login.php code is shown in Listing 11.


Listing 11. login.php
                
<?php
header( 'Content-type: text/xml' );
if ( $_POST['user'] == 'jack' && $_POST['password'] == 'password' )
  echo( "<ok/>" );
else
  echo( "<bad/>" );
?>

This simple code checks against a hard-coded value for the user and password, then returns ok if there is a match and bad otherwise.

For completeness, the home page code is shown in Listing 12.


Listing 12. home.html
                
<html>
<body>
  You are logged in and this is your home page.
</body>
</html>

To start the example in the browser, I bring up the page, type an invalid user name and password, and click Login. The result is shown in Figure 9.


Figure 9. The login page after typing an incorrect password
The login page after typing an       incorrect password

Then, when I change the user name and password to the correct values and click Login, I'm redirected to the home page shown in Figure 10.


Figure 10. The login page after typing the correct user name and password
The login page after typing the       correct user name and password

My last example for this article is an XForms-based Ajax article.



Back to top


XForms Ajax

I wouldn't consider myself an XForms expert, but I do find it a cool standard. In this article, I blend the client-side XForms stuff with Protoype.js and Ajax techniques.

The code for my simple XForms example is shown in Listing 13.


Listing 13. index.xhtml
                
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:xforms="http://www.w3.org/2002/xforms">
<head>
<title>XForms AJAX Example</title>
<xforms:model id="modelData">
 <xforms:instance xmlns="">
  <Data>
   <First>First</First>
   <Last>Last</Last>
   <Email>email@email.com</Email>
  </Data>
 </xforms:instance>
</xforms:model>
<script src="prototype.js"></script>
</head>
<body>
<xforms:input ref="/Data/First">
<xforms:label>First: </xforms:label>
</xforms:input><br/>
<xforms:input ref="/Data/Last">
<xforms:label>Last: </xforms:label>
</xforms:input><br/>
<xforms:input ref="/Data/Email">
<xforms:label>Email: </xforms:label>
</xforms:input><br/><br/>

<button onclick="submit()">Submit</button>
<script>
function submit()
{
 var m = $('modelData');
 var base = m.getElementsByTagName('Data')[0];
 var s = new XMLSerializer();
 var data = ( s.serializeToString( base ) ).toString();
 new Ajax.Updater( 'result', 'params.php', 
   { method: 'post', parameters: 'data='+escape( data ) } );
}
</script>

<br/><br/>
<div id="result">
</div>

</body></html>

At the top of the file is the XML model for the XForm. Then, there is a set of XForms labels and inputs that make up the form itself. The Submit button calls the submit() JavaScript function. This function then uses the XMLSerializer JavaScript object to turn the XForms data model into an XML string, which is then posted to params.php. The params.php script, shown in Listing 14, returns the XML as HTML so that you can see what comes out of the page.


Listing 14. params.php
                
<?php
echo( htmlentities( $_POST['data'] ) );
?>

When I bring up the XForms page in my browser (with the XForms add-on installed), I see something like Figure 11.


Figure 11. An Ajax-enabled XForms page
An Ajax-enabled XForms page

Then, when I fill in the form and click Submit, I see something like Figure 12.


Figure 12. The page after clicking Submit
The page after clicking Submit

This shows the data model that was turned into XML text, sent across to params.php, then returned into the result <div> tag.



Back to top


Conclusion

Share this...

digg Digg this story
del.icio.us Post to del.icio.us
Slashdot Slashdot it!

You can do so much with Ajax to enable HTML forms, and this article just scratches the surface. However, it should give you some ideas and practical examples of what you can do in your own applications with relatively easy modifications to your page code.




Back to top


Download

DescriptionNameSizeDownload method
Source code for forms applicationx-ajaxxml9-forms.zip101KBHTTP
Information about download methods


Resources

Learn

Discuss


About the author

Jack D. Herrington is a senior software engineer with more than 20 years of experience. He's the author of three books: Code Generation in Action, Podcasting Hacks, and PHP Hacks. He has also written more than 30 articles. You can reach Jack at jherr@pobox.com.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top