[ZPT] DRAMA: Can Formulator Play Nicely With ZPT? (Part II)

Jeffrey P Shell jeffrey@cuemedia.com
Fri, 11 Oct 2002 17:58:45 -0600


First - not the best attitude to have when seeking help.

Second - you would probably have gotten an answer faster on the 
zope@zope.org list.  There are more people there, and more Formulator 
users.  ZPT is a fairly focused mailing list.  There's even a dedicated 
Formulator mailing list which will probably be of better help, which 
you can find on the Formulator page on Zope.org

http://www.zope.org/Members/faassen/Formulator

On Friday, October 11, 2002, at 04:20  PM, beno wrote:

> Hi;
> This is my SECOND POST concerning this question. I KNOW someone out 
> there has the answer. Hopefully that person will be kind enough to 
> help...
>
> I'm trying to follow a recipe someone named *macquyver007* posted on 
> zopelabs for using Formulator. (I've done away with his check_form 
> script since I'm not interested in authenticating users.) Here's a 
> code snippet:
>
> <form name="email_us_formulator" method="post" action="email_us.zpt">
> Your Name:<br>
> <input tal:condition="python:request.has_key('field_Your Name')" 
> tal:attributes="value request/field_Your Name" name="field_Your Name" 
> type="text" id="field_Your Name">
>         <input tal:condition="python:not request.has_key('field_Your 
> Name')" name="field_Your Name" type="text" id="field_Your Name">

Alright.  Here's what I do with table based forms that I don't let 
formulator automatically render.  I use a table based form so I can (a) 
control layout, and (b) have some nice contexts.  If your id's have 
spaces in them - you're probably going to have problems.

1.<table tal:define="form here/myFormulatorForm">
2.  <tr tal:define="yourname 
request/YourName|some_other_data_source/YourName|nothing">
3.   <th align="left">Your Name:</th>
4.   <td><input type="text" name="YourName"
5.              tal:replace="structure 
python:form.YourName.render(yourname)">
6.   </td>
7. </tr>
8.</table>

On line 1, I make a handy shortcut that I can use in expressions inside 
of the table tag.

On line 2, I look for a value to populate the field with, looking first 
in the 'request' object (usually populated when doing error handling, 
depending on the method used), and then some other data source like a 
SQL record or another object, if this form is being used to edit items, 
finally setting the value to 'nothing' if those paths fail.

On line 4, I make the input tag.  But it could just be a span, could be 
any tag really, because I'm going to replace it.  I often sketch out my 
forms in GoLive first before adding the TAL annotations, and it's 
helpful to keep a tag that approximates the output.

Because on line 5, I do a tal:replace structure statement, calling the 
render method on the Field 'YourName' which is in the 
'myFormulatorForm' object.  This lets me use Formulator to decide 
details about each field - its size, max length, and other validation 
and enforcement settings, and have those get rendered properly at 
output time AND dealt with properly at validation time.

Using the code above, I don't have to have two versions of the same tag 
- one that responds to whether the request has the value, and one that 
doesn't.  Formulator will populate the field value with what I pass in 
to the 'render' tag, and will handle an empty value fine.

> My problems are these:
> Why doesn't the form validate? How do I make it validate?

If Formulator has the right information (depending on how you either 
populate your input tags, or generate them - which is why I use 
'tal:replace="structure ..."' - it helps ensure that Formulators 
validators get what they want), you can have a Python Script like the 
following:

from Products.Formulator.Errors import FormValidationError
request = container.REQUEST
errors = []
try: context.myFormulatorForm.validate_all_to_request(request)
except FormValidationError, e:
     errors = e.errors

## You can go through the errors list and build a structure
## like a dictionary to make hilighting error fields easier,
## or you can just loop through the errors in the return
## page to display error fields and the validation messages
## in a single block.
edict = {}
for error in errors:
     edict[error.field_id] = error.error_text

if errors:
     return context.restrictedTraverse('mytemplate.pt')(
         request, errors=errors, edict=edict,
         )
else:
     ## do success handler


> How do I incorporate a textarea? I've tried changing the *input* part 
> of the tag, but that simply makes the tag disappear!

There are a couple of different TextArea Formulator Fields.
<input tal:replace="structure python:form.aTextArea.render(value)">
and
<textarea tal:replace="structure python:form.aTextArea.render(value)">
</textarea>

will yield the same results.