dws has asked for the wisdom of the Perl Monks concerning the following question:

Has anyone come up with a clean way of checking arbitrary radio box inputs when using HTML::Template?

I'm using template to build a set of semi-complicated pages. Each page holds a form. When submitted, validation logic checks the consistency of the data that comes in via text fields, radio buttons, and a stray checkbox. If validation fails, I reissue the page with all of the input boxes filled in as they were, and a pithy message at the top explaining what's wrong.

Trying to maintin input state leads to a messy problem; one that I'm hoping someone has come up with a clean approach to.

Regenerating text fields is easy. The templates say

<input type=text name=foo value='<TMPL_VAR NAME="foo">'>
and as long as I've given the template a parameter binding for "foo", things work fine. A major plus is that I can view the template in a browser to verify formatting.

Radio buttons are a messier. I want to leave as much clean HTML in the template as possible. But how to regenerate them such that I don't lose the selection? I could do violence to the HTML, and write something like:

<input type=radio name=bar value="bar1" <TMPL_VAR NAME="bar1_checked">>
where "bar1_checked" will either be "" or "checked". But this screws up the HTML in the template, rendering it unviewable.

The other approach is to do something like

<TMPL_IF NAME="bar1_checked"> <input type=radio name=bar value="bar1" checked> <TMPL_ELSE> <input type=radio name=bar value="bar1"> </TMPL_IF>
around each radio box. The template is then viewable as HTML, though each box appears twice, which screws up formatting. To keep tables from getting screwed up, I resorted to writing
<TMPL_IF NAME="bar1_checked"> <tr> <td><input type=radio name=bar value="bar1" checked></td> <td>$47</td> </tr> <TMPL_ELSE> <tr> <td><input type=radio name=bar value="bar1"></td> <td>$47</td> </tr> </TMPL_IF>
but this bloated my templates something aweful, and requires that I invent a new template parameter per radio box. With a dozen radio boxes, the space ads up.

Does anyone know of a clean approach that will let me generate a page with arbitrary radio buttons checked, without having to break or bloat the HTML? Or am I S.O.L.?

P.S. JavaScript is not on option.

Replies are listed 'Best First'.
Re: HTML::Template and checking arbitrary radio buttons
by blokhead (Monsignor) on Jan 03, 2003 at 06:39 UTC
    I know I have often troubled with the same problems with dynamic <select> tags: they can be a big pain to put together entirely in the template. The HTML::Template FAQ (FAQ #11) suggests using the CGI module's form field generation functions, and simply passing the result to HTML::Template. I like this approach -- on the one hand, you definitely don't need to be bothered with generation of a <select> dropdown in your application logic, but on the other, it's still a disgusting TMPL_LOOP in the template, when logically it should just be one simple TMPL_VAR.

    There's no reason the same logic couldn't apply to your radio buttons -- have some facility to simply generate them inside your program (using CGI.pm or otherwise), and just use the results as a string to pass to a TMPL_VAR. Just make sure your application logic doesn't suffer because of it, i.e., still keep the HTML generation far away from the application logic. I swear I've seen threads about this very subject (with regard to <select> tags), but haven't been able to locate them. You may have better luck with your search terms.

    Assuming it's feasable to alter the templates you currently have in use to facilitate another TMPL_* tag, a very slick way to do this would be to wrap your HTML::Template calls in a pre-parser that will make the following simple translation:

    # change this in your template: <TMPL_RADIO PARAM="foo1" NAME="foo" VALUE="1"> <TMPL_RADIO PARAM="foo2" NAME="foo" VALUE="2"> # to this: <input type=radio name="foo" value="1" <TMPL_IF NAME="foo1">checked</TMPL_IF>> <input type=radio name="foo" value="2" <TMPL_IF NAME="foo2">checked</TMPL_IF>>
    Notice the addition of TMPL_RADIO. Take a gander at the filter argument to HTML::Template->new, which would allow you to do just this. Now when you (or your designers) edit the templates, they see one atomic TMPL_* tag without the ugliness of the TMPL_IF, the application code shouldn't need to be changed, and the nested tags don't show up until right before the HTML is passed to HTML::Template.

    Best of luck,

    blokhead

Re: HTML::Template and checking arbitrary radio buttons
by pfaut (Priest) on Jan 03, 2003 at 13:35 UTC

    My first impulse would be to do it like this.

    <input type=radio name=bar value="bar1" <TMPL_IF NAME="bar1_checked"> +checked</TMPL_IF>>

    I don't know if you would consider this as bad as your first approach but it's a little better than the second I think.

    --- print map { my ($m)=1<<hex($_)&11?' ':''; $m.=substr('AHJPacehklnorstu',hex($_),1) } split //,'2fde0abe76c36c914586c';
(jeffa) Re: HTML::Template and checking arbitrary radio buttons
by jeffa (Bishop) on Jan 03, 2003 at 18:17 UTC

    Guess i should throw my two cents in ...

    In less serious apps, i tend to bring in CGI.pm - but for a pure HTML::Template solution, i pass a param called 'checked' (most often this param is embedded to be used in a loop context) that is either undef or the value 'checked'. Then i can use something like:
    <input type="radio" name="bar" value="bar1" <tmpl_var checked> />
    I find this more elegant than using <tmpl_if>, but it is still a bit more work than i care to do on a regular basis (and the fact that it borks HTML editors doesn't bother me as i use gvim ). I really wish HTML::Template had methods to generate form elements like PHP's Smarty (but not too many - Smarty has lot's of methods that, IMHO, should not be there).

    Update:
    I also wish you could use square brackets for HTML::Template tags instead ...

    <input type="radio" name="bar" value="bar1" [tmpl_var checked] />
    Might be able to trick it with that 'Vanguard' compatibility mode ... but even if that worked, it's probably not safe.

    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)
    
Re: HTML::Template and checking arbitrary radio buttons
by tjmather (Initiate) on Jan 04, 2003 at 01:12 UTC
    Have you looked at HTML::FillInForm? It subclasses HTML::Parser to fill in HTML forms, including radio boxes.
Re: HTML::Template and checking arbitrary radio buttons
by shotgunefx (Parson) on Jan 03, 2003 at 18:23 UTC
    I haven't found a clean way. One way to do it is to install a Filter::Handle on STDOUT that hooks in HTML::Parser, then you rewrite the options and inputs as it outputs. If you are using CGI.pm then you can simply subclass it.

    -Lee

    "To be civilized is to deny one's nature."