blob: ae3d7adf313b5bb0d97ec89d4d0dafc59b2feace [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Cocoon Forms: A Simple Example</title>
<link href="http://purl.org/DC/elements/1.0/" rel="schema.DC">
<meta content="The Apache Cocoon Team" name="DC.Creator">
</head>
<body>
<h1>A simple CForms example</h1>
<p>In this example we will show how to create a simple registration
form using CForms and flowscript. We will follow to following steps:</p>
<ol>
<li>Create a form definition file</li>
<li>Create a template file for the Forms Template Transformer</li>
<li>Write a bit of flowscript</li>
<li>Add some pipelines to the sitemap</li>
</ol>
<p>Here is a screenshot of the form we're going to create:</p>
<div align="center">
<img class="figure" alt="Screenshot of the sample we're going to create." src="images/forms_registrationform.png"></div>
<h1>Create a form definition file</h1>
<p>Below the form definition file is displayed. This lists all the widgets
in the form, together with their configuration information.</p>
<pre class="code">&lt;fd:form
xmlns:fd="http://apache.org/cocoon/forms/1.0#definition"&gt;
&lt;fd:widgets&gt;
&lt;fd:field id="name" required="true"&gt;
&lt;fd:label&gt;Name:&lt;/fd:label&gt;
&lt;fd:datatype base="string"/&gt;
&lt;fd:validation&gt;
&lt;fd:length min="2"/&gt;
&lt;/fd:validation&gt;
&lt;/fd:field&gt;
&lt;fd:field id="email" required="true"&gt;
&lt;fd:label&gt;Email address:&lt;/fd:label&gt;
&lt;fd:datatype base="string"/&gt;
&lt;fd:validation&gt;
&lt;fd:email/&gt;
&lt;/fd:validation&gt;
&lt;/fd:field&gt;
&lt;fd:field id="age"&gt;
&lt;fd:label&gt;Your age:&lt;/fd:label&gt;
&lt;fd:datatype base="long"/&gt;
&lt;fd:validation&gt;
&lt;fd:range min="0" max="150"/&gt;
&lt;/fd:validation&gt;
&lt;/fd:field&gt;
&lt;fd:field id="password" required="true"&gt;
&lt;fd:label&gt;Password:&lt;/fd:label&gt;
&lt;fd:datatype base="string"/&gt;
&lt;fd:validation&gt;
&lt;fd:length min="5" max="20"/&gt;
&lt;/fd:validation&gt;
&lt;/fd:field&gt;
&lt;fd:field id="confirmPassword" required="true"&gt;
&lt;fd:label&gt;Re-enter password:&lt;/fd:label&gt;
&lt;fd:datatype base="string"/&gt;
&lt;fd:validation&gt;
&lt;fd:assert test="password = confirmPassword"&gt;
&lt;fd:failmessage&gt;The two passwords are not equal.&lt;/fd:failmessage&gt;
&lt;/fd:assert&gt;
&lt;/fd:validation&gt;
&lt;/fd:field&gt;
&lt;fd:booleanfield id="spam"&gt;
&lt;fd:label&gt;Send me spam&lt;/fd:label&gt;
&lt;/fd:booleanfield&gt;
&lt;/fd:widgets&gt;
&lt;/fd:form&gt;
</pre>
<p>All elements are in the Forms Definition namespace: <strong>fd</strong>.</p>
<p>Every definition file has a <strong>&lt;fd:form&gt;</strong> element as the root element.</p>
<p>The child widgets of the form are defined inside the <strong>&lt;fd:widgets&gt;</strong> element.
As you can see, most of the widgets are field widgets. The field widget is the most
important widget in CForms. It is very flexible because it can be associated with
different datatypes and with a selection list. See the reference docs for more
information on this and other widgets.</p>
<p>A nice feature is that the <strong>fd:label</strong> tags can contain mixed content.
On the one hand, this can be used to provide rich formatting in the label. But it
also enables you to put i18n-elements in there, to be interpreted by the I18nTransformer.
This way, internationalisation is done using standard Cocoon techniques.</p>
<h1>Create a template file for the Forms Template Transformer</h1>
<p>Here's the template for our registration form example:</p>
<pre class="code">&lt;html xmlns:ft="http://apache.org/cocoon/forms/1.0#template"
xmlns:fi="http://apache.org/cocoon/forms/1.0#instance"&gt;
&lt;head&gt;
&lt;title&gt;Registration form&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Registration&lt;/h1&gt;
&lt;ft:form-template action="#{$continuation/id}.continue" method="POST"&gt;
&lt;ft:widget-label id="name"/&gt;
&lt;ft:widget id="name"/&gt;
&lt;br/&gt;
&lt;ft:widget-label id="email"/&gt;
&lt;ft:widget id="email"/&gt;
&lt;br/&gt;
&lt;ft:widget-label id="age"/&gt;
&lt;ft:widget id="age"/&gt;
&lt;br/&gt;
&lt;ft:widget-label id="password"/&gt;
&lt;ft:widget id="password"&gt;
&lt;fi:styling type="password"/&gt;
&lt;/ft:widget&gt;
&lt;br/&gt;
&lt;ft:widget-label id="confirmPassword"/&gt;
&lt;ft:widget id="confirmPassword"&gt;
&lt;fi:styling type="password"/&gt;
&lt;/ft:widget&gt;
&lt;br/&gt;
&lt;ft:widget id="spam"/&gt;
&lt;ft:widget-label id="spam"/&gt;
&lt;br/&gt;
&lt;input type="submit"/&gt;
&lt;/ft:form-template&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>The CForms-specific elements here are in the "Forms Template" namespace: <strong>ft</strong>.</p>
<p>The &lt;ft:widget-label&gt; tag will cause the label of a widget to be
inserted at the location of the tag. The &lt;ft:widget&gt; tag will cause
the XML representation of a widget to be inserted at the location of that tag.
The inserted XML will be in the "Forms Instance" namespace: <strong>fi</strong>.</p>
<p>The XML representation of the widget will then be translated to HTML by an
XSLT stylesheet (forms-samples-styling.xsl in our case -- see sitemap snippets below).
This XSLT only has to handle individual widgets, and not the page as a whole,
and is thus not specific for one form but can be reused across forms.</p>
<p>For certain widgets it may be necessary to provide extra presentation hints,
such as the width of a text box, the style of a selection list (drop down,
radio buttons, ...) or class and style attribute values. This can be done
by putting a fi:styling element inside the ft:widget element. This element
is in the fi namespace because it will be copied literally. The attributes
and/or content of the fi:styling element depend on what is supported by the
particular stylesheet used.</p>
<p>As an alternative to the template approach, you could also use the FormsGenerator,
which will generate an XML representation of the whole form, and style that with a
custom-written XSLT. For most users we recommend the template approach though.</p>
<h1>Write a bit of flowscript</h1>
<p>Flowscript is Cocoon's solution to handling the flow of a web interaction.
It is based on the concept of continuations. If you don't know yet about continuations
and flowscript, <a href="../flow/index.html">learn about it here</a>.</p>
<p>Here's the flowscript for our example, <span class="codefrag">registration.js</span>:</p>
<pre class="code">cocoon.load("resource://org/apache/cocoon/forms/flow/javascript/Form.js");
function registration() {
var form = new Form("forms/registration.xml");
form.showForm("registration-display-pipeline");
var model = form.getModel();
var bizdata = { "username" : model.name }
cocoon.sendPage("registration-success-pipeline", bizdata);
}</pre>
<div class="note">This sample still shows the "old" flowscript API. Will be updated eventually.</div>
<p>The flowscript works as follows:</p>
<p>First we create a Form object, specifying the form definition file to be used.
The Form object is actually a javascript wrapper around the "real" Java form instance object.</p>
<p>Then the showForm function is called on the form object. This will (re)display
the form to the user until validation of the form succeeded. As parameter to
the showForm function, we pass the sitemap pipeline to be used to display the form.</p>
<p>Finally we get some data from the form (the entered name), and call a sitemap
pipeline to display this data. This pipeline is based on the JXTemplate generator.</p>
<h1>Add some pipelines to the sitemap</h1>
<p>First of all, do not forget to register the <span class="codefrag">registration.js</span>
file in the map:flow section of the sitemap, as follows:</p>
<pre class="code">&lt;map:flow language="javascript"&gt;
&lt;map:script src="flow/registration.js"/&gt;
&lt;/map:flow&gt;</pre>
<p>And here are the pipelines we need:</p>
<pre class="code">&lt;map:match pattern="registration"&gt;
&lt;map:call function="registration"/&gt;
&lt;/map:match&gt;
&lt;map:match pattern="*.continue"&gt;
&lt;map:call continuation="{1}"/&gt;
&lt;/map:match&gt;
&lt;map:match pattern="registration-display-pipeline"&gt;
&lt;map:generate src="forms/registration_template.xml"/&gt;
&lt;map:transform type="forms"/&gt;
&lt;map:transform type="i18n"&gt;
&lt;map:parameter name="locale" value="en-US"/&gt;
&lt;/map:transform&gt;
&lt;map:transform src="resources/forms-samples-styling.xsl"/&gt;
&lt;map:serialize/&gt;
&lt;/map:match&gt;
&lt;map:match pattern="registration-success-pipeline"&gt;
&lt;map:generate type="jx" src="forms/registration_success.jx"/&gt;
&lt;map:serialize/&gt;
&lt;/map:match&gt;</pre>
<p>The first two are for managing the flowscript: when someone hits the registration
URL, we call the registration function in our flowscript.</p>
<p>When a form is submitted, it will be matched by the second matcher,
*.continue, which will continue the execution of the flowscript.</p>
<p>The third matcher is for displaying the form, and uses the Forms Template Transformer.</p>
<p>The fourth pipeline is for showing the "success" page using the
JXTemplate generator, here is the contents of the registration_succcess.jx page:</p>
<pre class="code">&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Registration successful&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
Registration was successful for ${username}!
&lt;/body&gt;
&lt;/html&gt;</pre>
<h1>Next steps</h1>
<p>The example we've studied here is quite simple. To have a feel for the power
of CForms, take a look at the examples included included in the Forms block.</p>
</body>
</html>