This HOWTO is intended to give an introduction to the use of Formulator from the Zope Management Interface and from DTML, although much of this applies to use from ZPT or Python as well. Note that Formulator comes with online help for each tab as well as API help, so be sure to check that as well. This document will only give an overview of the possibilities and not all the details.
Formulator is a tool to create and validate web forms in Zope. Formulator takes care of the rendering of the fields in the form, as well as the validation and processing of the data that is submitted. Formulator's scope is limited to forms: "do web forms, web forms only, and web forms well." Formulator does currently not even take care of the precise layout of a form -- each form is layouted differently and thus layout is left to the developer. Formulator does allow for easy integration with external systems, however.
It is easy to create a Formulator Form, just pick it from the add
list and add it to a folder. I usually only have one form in a
folder and call it form
to make automatic layout handling
easier; I'll say more about the reason for this later.
The default view of the form looks just like a folder, except that the only things that are addable are Formulator Fields. When you add a field to a form, it'll show up in the Form, just like an object shows up in a normal Zope Folder.
When you click on a field, you see a list of its properties in the
field's Edit
screen. This is a good time to explain that
Formulator has an extensive help system, and that if you click on
help
in the Edit
screen you'll see a list with a short
description of what each property does.
If you click on the Test
tab in the Field, you will see the
field displayed as it would appear in the form. If you fill in
some value in the field and click on the Test
button, you can
test its validation behavior. If everything could be validated and
processed all right, you'll see the resulting value. If it could
not be validated however, you see an error, showing the error_key
and error_text.
The best way to learn about what the different fields do and how their properties work is to try them out. Just change some properties and see what happens in the Test screen. And be sure to look at the help.
The form Test
tab is not difficult to explain; it shows all the
fields you have added to the form. You can test the behavior of
the entire form here.
In the Order
part you can group fields and order them inside
their groups. The order determines the order in which they appear
on the Test
screen, and can also can be used in your own
code. Initially there is only a single Default
group, but you
can add new groups and change their names.
In the Settings
tab you can determine the form properties. You
can set the form submit action and method here, which you can
later use with the header()
and footer()
methods of the form.
The field Override
screen allows you to make the field call an
override method (most commonly a Python Script) for a property.
Instead of using the property value in the Edit
screen, the
method with the name listed in the override tab will be called to
retrieve a value then. The returned value must be the same as the
one that property's field generates; for an IntegerField this is
an integer, for instance. The titles of overridden fields will be
displayed between square brackets ([ ]
) in the Edit
screen.
In the Messages
screen you can set the text of the error
messages that field can generate upon validation errors.
All the examples in this HOWTO are contained in the file
formulator_howto_examples.zexp
, which you can download from the
Formulator product page
(http://www.zope.org/Members/faassen/formulator) and import into
your Zope. In the examples, all the forms are called form
.
manual
folder) First, I will show how to use DTML to manually layout a form. This
takes the most work, but also allows the most flexibility. In all
these examples I will assume the form is called form
.
The form contains three fields; a StringField animal
, a
StringField color
, and an IntegerField number
. index_html
is
the DTML Method that does the manual layout:
<dtml-var standard_html_header> <!-- show the header of the form, using 'Form action' and 'Form method' form settings (<form action="..." method="...">) --> <dtml-var "form.header()"> <!-- a simple table for layout purposes --> <table border="0"> <!-- each field will be on a line by itself --> <tr> <!-- first display the title property of the animal field --> <td><dtml-var "form.animal.get_value('title')"></td> <!-- render the field --> <td><dtml-var "form.animal.render()"></td> </tr> <!-- the same for the color field --> <tr> <td><dtml-var "form.color.get_value('title')"></td> <td><dtml-var "form.color.render()"></td> </tr> <!-- and the number field --> <tr> <td><dtml-var "form.number.get_value('title')"></td> <td><dtml-var "form.number.render()"></td> </tr> <!-- the submit button --> <tr> <td><input type="submit" value=" OK "></td> </tr> </table> <!-- the form footer --> <dtml-var "form.footer()"> <dtml-var standard_html_footer>
This shows a form with the three fields. You can easily rearrange the layout just by changing the HTML.
automatic
folder) For many simple forms you don't need to do the layout yourself all
the time. We can use Formulator and acquisition to make layout a
lot easier. If we know each form is in a separate folder and is
called form
, we can place DTML method in the root of the site
that can render any such form. In this example index_html
will
do the automated rendering directly. In real-world sites you'd
usually use another method (for instance called form_body
) to
render because not all folders would contain forms. In that case
it'd be easier to put the form rendering code in another method
(for instance called form_body
), which you can then call from
your other code. Here's 'index_html':
<dtml-var standard_html_header> <!-- show the header of the form, using 'Form action' and 'Form method' form settings (<form action="..." method="...">) --> <dtml-var "form.header()"> <!-- a simple table for layout purposes --> <table border="0"> <!-- get a list of all fields in the form --> <dtml-in "form.get_fields()"> <!-- rename each sequence item to 'field' so they can be used more easily --> <dtml-let field=sequence-item> <!-- each field will be on a line by itself --> <tr> <!-- display the title property of this field --> <td><dtml-var "field.get_value('title')"></td> <!-- render the field --> <td><dtml-var "field.render()"></td> </tr> </dtml-let> </dtml-in> <!-- the submit button --> <tr> <td><input type="submit" value=" OK "></td> </tr> </table> <!-- the form footer --> <dtml-var "form.footer()"> <dtml-var standard_html_footer>
The nice thing about the automatic approach is that now you can change the Formulator form as much as you like; this code will always automatically display them. Even better, if you add subfolders with forms in them, acquisition makes those forms display automatically as well! If you have only simple forms on a site, this could be the only DTML Method you need.
validation
folder) I will use the same index_html
as in the automatic form
rendering example and the animal/color/number
form to
demonstrate form validation.
I've set the Form action
property of the form to feedback
.
When the form is submitted it, Zope will access the feedback
DTML Method. The form data will be coming into feedback
in the
REQUEST
object (more precisely the REQUEST.form
object).
feedback
method should do a number of things: Here's feedback
, with comments:
<dtml-var standard_html_header> <dtml-try> <!-- try the validation, results should be put in REQUEST (keyed under the field id) --> <dtml-call "form.validate_all_to_request(REQUEST)"> <dtml-except FormValidationError> <!-- if something went wrong with any field validation, a FormValidationError will be raised, which we will then catch here --> <!-- we will display the errors here --> <ul> <dtml-in "error_value.errors"> <li> <dtml-var "field.get_value('title')">: <dtml-var error_text> </li> </dtml-in> </ul> <dtml-else> <!-- if no FormValidationError was raised, we're done with validation and our results will now be in REQUEST (and in DTML namespace). --> <!-- we could do anything with them, but we'll simply display them --> Hah, you are a <dtml-var color> <dtml-var animal> with <dtml-var number> legs. </dtml-try> <dtml-var standard_html_footer>
Note that often you can use acquisition with the validation page as well, so you can reuse most of its functionality.