Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Sticky Forms with HTML::Template

by seattlejohn (Deacon)
on Dec 28, 2002 at 19:21 UTC ( [id://222769]=perlmeditation: print w/replies, xml ) Need Help??

I'm building a CGI application where I need to have forms that retain state between invocations. You know the type: You fill out a bunch of fields on a page and hit submit, and when the validator discovers that some of your responses are impermissible, or you need to back up for whatever reason, you get a form whose form elements are just as you entered them -- no re-typing. The forms may contain items like checkboxes, radio buttons, and multiple-select lists in addition to text fields. I've come up with an approach that works, but I'd love to hear how other monks have approached this problem and see if there's a more elegant solution in the offing.

It's easy enough to build sticky forms if you use the HTML-generation methods/functions in CGI.pm. But I'm a strong proponent of isolating presentation (HTML) from business logic, so I didn't want to create forms by writing a bunch of code. Instead I wanted a way to leverage the templating system I was already using -- HTML::Template.

I thought about using the logical constructs in HTML::Template to try to create sticky form widgets, but in addition to feeling clumsy, that seemed like an inordinate amount of work. I also looked at HTML::StickyForms, but it didn't seem to offer much that isn't already provided by CGI. HTML::FillInForms looked more promising but I wasn't thrilled by the fact that it relies on HTML::Parser, which seems like it would add a lot of overhead on complex pages. (I'm aware that I could be falling into the premature-optimization trap here, but I wanted to at least explore lighter-weight alternatives.)

The solution I eventually tried was to build a bridge between HTML::Template variables and the sticky form-generation capabilities of CGI. I defined a way to denote form elements using HTML::Template variables. Then my sub that instantiates and populates the template looks for all the template variable names that match a certain pattern, and calls the appropriate CGI element generator to set the value for that template variable. So my form templates now have sections that look something like this:

Your name: <TMPL_VAR NAME="FORM_TEXTFIELD_NAME"><br> Your favorite pastimes: <TMPL_VAR NAME="FORM_LIST_PASTIMES">
The basic attributes (field type and name) of the form elements are encoded in the name of the template variable. Field-specific parameters are stored in a hash keyed on the field name, which both allows me to generate items programmatically and avoids requiring some way to encode this information in the template variable name. It also means that if I'm careful about my field naming, multiple templates could refer to a field that will always have the same attributes (for example, a username might always be maxlength=15, size=15, regardless of which form it's on).

This all seems to work fine. But I'd love to get feedback from the folks in this community and also to hear of any other approaches that monks have found fruitful.

        $perlmonks{seattlejohn} = 'John Clyman';

Replies are listed 'Best First'.
(jeffa) Re: Sticky Forms with HTML::Template
by jeffa (Bishop) on Dec 28, 2002 at 19:37 UTC
    Did you try associate first? From the docs:
    
       associate - this option allows you to inherit the
       parameter values from other objects.  The only
       requirement for the other object is that it have a
       param() method that works like HTML::Template's
       param().  A good candidate would be a CGI.pm query
       object.  Example:
    
         my $query = new CGI;
         my $template = HTML::Template->new(
            filename => 'template.tmpl',
            associate => $query
         );
    
       Now, $template->output() will act as though
    
         $template->param('FormField', $cgi->param('FormField'));
    
       had been specified for each key/value pair that
       would be provided by the $cgi->param() method.
       Parameters you set directly take precedence over
       associated parameters.
    

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      I looked at associate, but I couldn't think of a straightforward way to make it work with things like multi-select list boxes.

              $perlmonks{seattlejohn} = 'John Clyman';

        Yes, you are correct about select boxes - read samtregar's HTML::Template FAQ number 11 and you will see that your method is actually quite sound (he recommends using CGI.pm - see Re: TMPL_LOOP within a TMPL_LOOP). Perhaps a combination of associate and CGI.pm's popup_menu() and scrolling_list() would make for an elegant solution. Cheers :)

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://222769]
Approved by Zaxo
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (7)
As of 2024-04-23 11:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found