An introduction to XForms submission

Mark Birbeck's picture

This introduction contains a high-level look at XForms submission. For those new to a declarative approach to programming it's probably easier to understand what XForms submission does by looking at the kinds of procedural code it replaces. Since the approach most familiar to web programmers will be the use of JavaScript in an Ajax application we'll begin there, before then moving on to XForms.

Ajax submission

Ajax emphasises asynchronous programs, by way of JavaScript. Programmers used to languages such as Java or C++ will probably find the idea quaint. But as the explosion of interest in Ajax in the last few years has shown, programmers using HTML forms as their application's front-end were crying out for a way to remove unnecessary round-trips to the server and page refreshes.

There are a number of ways this can be achieved in Ajax programming, but the most common is to avoid using HTML forms, and instead use a separate object which can retrieve data directly. This data can then be used to update small parts of the display, and of course dramatically improves the user experience.

The script

Recall that the only reason we're looking at the way data is transferred using script, is as a way to understand what it is that XForms is making easier. If you're looking at XForms with an Ajax background, then this will be useful information, but if you've not used script or Ajax before, don't feel the need to learn any of the following constructs--just try to get a high-level view.

The most common way of doing an Ajax request is to set up script like this:

var req;

function loadXMLDoc(url) {
  // native XMLHttpRequest object
  if (window.XMLHttpRequest)
  {
    req = new XMLHttpRequest();
    req.onreadystatechange = readyStateChange;
  // IE/Windows ActiveX version
  } else if (window.ActiveXObject)
    req = new ActiveXObject("Microsoft.XMLHTTP");

  if (req);
  {
    req.onreadystatechange = readyStateChange;
    req.open("GET", url, true);
    req.send();
  }
}

function readyStateChange() {
  // '4' means document "loaded"
  if (req.readyState == 4)
  {
    // HTTP 200 means "OK"
    if (req.status == 200)
    {
      // do something here
    } else
    {
      // error processing here
    }
  }
}

loadXMLDoc("http://example.com/customers/my-customer.xml");

A more complete approach would look to handle the error conditions, allow more than one submission to be running at the same time, and so on. But since that would make the code more complicated, not less, the snippet we have gives us plenty to help us understand what it is that a data submission is generally doing.

The XForms equivalent

Let's map the procedural code that we've just seen to the XForms equivalent:

<xf:submission method="get" action="http://example.com/customers/my-customer.xml">
  <xf:action ev:event="xforms-submit-done">
      <!-- do something here -->
  </xf:action>
  <xf:action ev:event="xforms-submit-error">
      <!-- error processing here -->
  </xf:action>
</xf:submission>

Here we can see that we've specified the same things that we did in the Ajax approach--the URL that we want to get data from, the actions to perform if there is an error, and so on--but the difference here is that this is all we've had to do. Everything else involved in the submission has been done for us.

Submission as a pattern

This idea of simply 'filling in the blanks' will be very familiar to anyone who takes a 'pattern' approach to their development. By re-using commonly occurring programming 'patterns', programmers are able to develop applications more quickly and more accurately. A pattern is not necessarily a library of code though, but is more a set of relationships between high-level, abstract components.

Let's think of our XForms submission processing as a pattern. What we have is some behaviour that is defined in a pretty abstract way, along the following lines:

'get' some data from one URL, or 'put' some data to another URL, and when done, generate either a 'success' event or a 'fail' event.

The strength of any pattern is in the fine balance between being sufficiently general that it can apply to many situations, but not so general that it says nothing. In this case it does seem quite vague; all we seem to have said is 'get a document from here and put it there, and let me know when you've finished'. But when you think about it, that pretty much covers most of the basics for a lot of things we'd like to do: sending an email, saving a file to disk, retrieving an RSS feed, posting a document to a server, and so on. It certainly captures the basic Ajax request we looked at earlier.

By operating at such a high-level of abstraction, we provide a lot of power to the programmer whilst also reducing the amount that they need to learn to perform new tasks.

Reading data from files

To illustrate, let's look at the XForms mark-up for retrieving a file from disk:

<xf:submission
 method="get" action="file:my-customer.xml"
/>

As you can see, unlike with other programming paradigms, no new API is needed to make the shift from HTTP to the file system. In other words, any author/programmer who mastered the most common technique--getting and putting data to or from an HTTP server--has already got the complete skill-set for getting and putting the same document to or from the hard-drive.

Note also that if the code was written as a relative path:

<xf:submission
 method="get" action="my-customer.xml"
/>

then the same XForm would work regardless of whether it was running on a server, or being loaded from a local disk.

Sending an email

Let's go further and see what new skills our author needs to acquire to send the same XML document by email--and whether we can save them the cost of buying a book on MAPI, and the time needed to read it:

<xf:submission
 method="put" action="mailto:john.doe@example.com?subject=Results"
/>

As before, no new API to learn. No need to roll your sleeves up and get to grips with MAPI so that you can write a powerful application that will allow a user to enter some XML data, validate it, and then send it via email.

The declarative approach

This 'hiding' of functionality is the key point. It's not that we've hidden a whole load of script behind a set of libraries or common functions--which of course it goes without saying that we have--but rather that in XForms we have a simple language that captures an enormous amount of generic functionality. But crucially, that generic language still allows us to use the functionality in very specific situations.

To put it the other way round, we still get specific functionality, such as saving files, sending emails, storing data in a database, and so on, but without having to learn lots of specific APIs. (And we haven't even begun to look at the other features this simple pattern captures, from validation through to different data serialisation options, which make this an even more powerful technique than we've seen so far.)

In the following sections will look at how to use the power of submission in more detail.