You are not logged in Log in Join
You are here: Home » Members » jspisak » Wizards Made Easy

Log in
Name

Password

 

Wizards Made Easy

Purpose

The purpose of this How-To is to give developers an easy way of creating multiple step form wizards to create ZClass instances.  However, the concept can be applied to any multiple step HTML form process with Zope.

A Wizard With No Spells

In DTML the REQUEST object holds all the data from an HTML form.  Typically when creating ZClass instances, an 'addForm' is created by default for entering a small amount of properties.  When developing web application the need arises to have many ZClass instances or objects created at once by a single set of user interfaces or a 'wizard'.   When using DTML,  variables from a previous request can be passed on using the present form using 'hidden' inputs.

<input type="hidden" name="myFormData:string" value="<dtml-var "REQUEST['myFormData']">">

The above code tells Zope to use the value for 'myFormData' that is stored in the REQUEST from the previous form, as the value for a 'hidden' input of the same name.  This method has apparent limitations when the more than two forms are involved.  Each input name must be hand transcribed into the next form in the process.  This allows room for spelling errors or forgotten properties which can bring a developer to the point of mental explosion looking for the devil in the details.
 

Fill Out a REQUEST.form()

Every form in a REQUEST has its values and keys stored in a Python dictionary.  Using the REQUEST.form() dictionary we can iterate over the items in it and grab our 'hidden' inputs from there.  A dictionary in is a Python data structure that has keys and values.  We can get all of a form's data by iterating over the form using the 'dtml-in' tag.  When we reference a 'form', it has a method 'items' which contain the values as 'sequence-item's and their names as 'sequence-key's.
 

 <dtml-in "REQUEST.form.items()">
    <input type="hidden" name="<dtml-var sequence-key>" value="<dtml-var sequence-item>">
 </dtml-in>

This simple but powerful three lines shows the power of Zope.

What Do You Mean My Name Isn't On The List?

The above code will satisfy a developer's craving to cast their first  wizard magic, but it only works for text, strings, floating-point numbers, and integer properties.  What if an item in the wizard is a list?  Tokens and Lines properties are in effect Python lists.  These are a bit more ellusive, but with a good wand like DTML, they can be made to behave.  If the item in the REQUEST.form() can be sliced, and has at least one item in it, then it is a list.  Once the developer knows that it is a list, then the 'hidden' input can get written with a 'list' trinket.   This tells Zope to watch for other inputs with the same name and append them into a list.

 <dtml-in "_.range(0,_.len(REQUEST.form.keys()))">
   <dtml-let a=sequence-item>
    <dtml-try>
     <dtml-in "REQUEST.form.values()[a]">
      <dtml-if "_['sequence-item'] != ''">
       <input type="hidden" name="<dtml-var "REQUEST.form.keys()[a]">:list" value="<dtml-var sequence-item>">
      </dtml-if>
     </dtml-in>
    <dtml-except>
     <input type="hidden" name="<dtml-var "REQUEST.form.keys()[a]">" value="<dtml-var "REQUEST.form.values()[a]">">
    </dtml-try>
   </dtml-let>
 </dtml-in>

Notice the 'dtml-let'  tag being used to get around a need for a nested 'sequence-item'.  With a modest 13 lines of code, any values and keys in REQUEST.form() can be passed along in wizards to the developer's heart's content.  This allows the developer to build a simple, structured user interface to complex processes that would otherwise require legnthy, sizable HTML pages, and headaches.