http://www.perlmonks.org?node_id=135865

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

Hey everyone

I have been working on a small CGI script lately, and things have been going well. However, I have come up against a sort of problem.

My main goal so far of this "project" is to simply: Retrieve data from MySQL via the DBI module -> display this data in HTML form -> make a form for someone to input a row in the MySQL DB -> display contents of DB again in HTML form.

So far, everything but one of those parts of the project so far are completed. The part I don't know how to do yet is the form part. I am using HTML::Template for all of the HTML part, and am not sure how I can use a form with this (since I don't want to mirror too many cases or loops in the template that could have been done in the acutal .pl/.cgi program.

I did take a long look at this node: Q / A and HTML::Template techniques... and got some ideas as to how to do this *kind of*. But I don't know quite where to go with the code I have come up with which is displayed here:
#!/usr/bin/perl -w use strict; use HTML::Template; use CGI; use CGI::Carp qw(fatalsToBrowser); my $cgi = new CGI; print $cgi->header; my $template = new HTML::Template(filename => "1.tmpl", die_on_bad_par +ams => 0); $template->param( BOX => $cgi->popup_menu(-name=>'color', -values=>['red','green','blue','chartreuse'] +), BOX2 => $cgi->textfield('name'), ); print $template->output();

Also here is the .tmpl file:
<html> <title>test</title> <body> <form> <table border=1 > <tr> <td> Color1: <TMPL_VAR NAME="BOX"> <br></td> <td> What is your name?: <TMPL_VAR NAME="BOX2"> <br> </td> <td> <input type=submit> </td> </table> </form> </body> </html>

Hopefully my question(s) are clear enough to answer, or at least to point to where I can find out how to do it in a correct manner. Thanks for any and all help or comments regarding this question!

Andy Summers

Replies are listed 'Best First'.
Re: HTML::Template Form Usage
by rob_au (Abbot) on Jan 03, 2002 at 04:39 UTC
    since I don't want to mirror too many cases or loops in the template that could have been done in the acutal .pl/.cgi program

    I have to say that to a certain extent you are ignoring the true idea behind template integration to separate design and code. The usage of the CGI generated HTML to fill in HTML::Template variables defeats the purpose of using HTML::Template in the first place.

    Imagine, the scenario where you are working in a development team where it is decided that your role is solely to develop code and the role of HTML and interface design is assigned to someone else. The best way to provide the flexibility of allowing these two roles to co-exist effectively is decided to be to make use of a templating system such as HTML::Template or Template::Toolkit. So both you and the web designer set about your respective tasks yet when it comes to integrating the form template with the CGI script, the web designer finds that their work has been invalidated through your usage of CGI-generated HTML in the template variables passed. Furthermore, think of the headache 18 months down the track when you have moved on to other things and the company wants to hire a web designer to redesign their web page ... Your usage of CGI-generated HTML in the template variables would create much heartache for the poor designer hired to edit the HTML templates.

    This post is designed merely to get you thinking about the design philosophy you are taking with this usage of HTML::Template - You are rightly attempting to give yourself every opportunity to separate your design and code, yet at the same time hobbling the two together through the generation of HTML formatting by CGI rather than using the in-built templating features of HTML::Template. Admittedly in this instance, your generation of HTML by way of CGI is basic, but when I read through your code, the hairs at the back of my neck still stood on end at the thought of what it represented.

    If you are finding HTML::Template too limiting with regard to template logic and layout, you may want to consider the more powerful Template::Toolkit option. But try to avoid generating your HTML from your CGI script if you are using a templating system - You are merely taking a step backwards and again hobbling code and design back together.

     

    Update

    I had a closer look at your code and template and it appears that there is nothing there which you are displaying as a result of code generation. I'm aware that this may be a cut-down example, but if you are not actually displaying anything in your HTML page that is a result of code or process logic, then why not just stick with a plain HTML page - The real power of templating is realised when you are seeking to incorporate code or process output into a display or page, not simply page formatting.

     

    perl -e 's&&rob@cowsnet.com.au&&&split/[@.]/&&s&.com.&_&&&print'

(jeffa) Re: HTML::Template Form Usage
by jeffa (Bishop) on Jan 03, 2002 at 06:08 UTC
    What rob_au said is mighty true bladx. So I will focus on something else: CGI forms.

    What you are missing is the action attribute for the <form> tag. Also you are missing the fact that you don't have to have one template param for the text box and another for the value ... but let's back up a bit and slim this puppy down.

    The following is a super simple CGI script. Save this, run it, study it, know it:
    use strict; use CGI qw(:standard); my $box; print header, start_html('test'), start_form, textfield(-name=>'box',-override=>1), submit('go'), end_form; if ($box = param('box')) { print 'You submitted' . div({style=>'display: inline; color: red'}, +$box); }
    It is called a reentrant script, because it does one of two different things depending upon what parameters it finds:
    1. if "box" was not found, then this is the first time 'through the script' - ask the question
    2. if "box" is found, then this is the second time - parse the answer
    Instead of just 'giving the answer', i also 'ask the question' again, to keep the user from having to go back themselves. And actually, there is no 'second time' - only the first time and 'the rest'. What if the answer is wrong? What if the user didn't give any answer? These questions are the 'business rules', and are not even addressed here. This script only shows the user what they submitted, or nothing if they press 'go' without giving an answer. You should be able to figure out how to add the code that pulls and stores values from your database to this framework now that you see how to get params from the user.

    Now, how does this look when used with HMTL::Template? First off, go back to HTML::Template Tutorial and re-read 'Bag of Tricks' which describes associate. Here is the HTML::Template version:

Re: HTML::Template Form Usage
by jarich (Curate) on Jan 03, 2002 at 09:44 UTC
    ...Retrieve data from MySQL via the DBI module -> display this data in HTML form -> make a form for someone to input a row in the MySQL DB ...

    ...But I don't know quite where to go with the code I have come up with which is displayed here:

    I'm guessing that being told to use HTML::Template isn't exactly what you're looking for here, although it's very good advice.

    If you're looking for advice on what to do to your code from here, such that you can do the DBI lookup, show the table entries and then offer an addition form then you might do the following:
    tmpl file

    <html> <title>test</title> <body> <TMPL_IF NAME=data> Your row was added in successfully.<p> </TMPL_IF> <h1>Data already in table</h1> <table> <TMPL_LOOP NAME=data> <tr> <td>Name:</td><td><TMPL_VAR NAME=box2></td> <td>Colour1:</td><td><TMPL_VAR NAME=box></td> </tr> </TMPL_LOOP> </table> <form> <table border=1 > <tr> <td> Color1: <TMPL_VAR NAME="BOX"> <br></td> <td> What is your name?: <TMPL_VAR NAME="BOX2"> <br> </td> <td> <input type=submit> </td> </table> </form> </body> </html>
    I'm sure you can edit your cgi code appropriately to fill in that loop. Abstracting the html around the loop into your template file allows you to later change the back-grounds of your table rows or data or their fonts or many other things without having to wade through your code again. Of course if you don't like HTML source, you might not realise the benefit of this today.

    Whether or not this duplicates loops depends on your code. If you do a query, then loop through all the results pushing the hashrefs you've fetched into an array and then give that to the template to loop through and display you've duplicated a loop. Perhaps you'd think it better to build your table inside your CGI code and then add that to a variable which you then display.

    HTML::Template purists will hate that idea, and they should, because you'd be perverting a very powerful and beautiful tool, but if it's the best solution you have, then use it. Then again, I'd encourage you not to be afraid of having two similar loops here (using TMPL_IF to replace possible null fields with &nbsp might also help).

    Jacinta

      HTML::Template purists will hate that idea, and they should, because you'd be perverting a very powerful and beautiful tool, but if it's the best solution you have, then use it. Then again, I'd encourage you not to be afraid of having two similar loops here (using TMPL_IF to replace possible null fields with   might also help).

      One little problem with the TMP_IF scenario is that, at least with HTML::Template version 2.4, a variable was classified as defined simply by it being passed to the template via the $template->param method. The value of the variable was not interpolated and this approach wouldn't work because although the variable is undefined, the act of simply passing it to the template would result in the variable being classified as 'defined' and able to be displayed.

      The solution I found was to make use of the HTML::Template extension module HTML::Template::Expr which allows conditional expressions to also be incorporated into the template file and as such gives you greater control over variable "definition".

       

      perl -e 's&&rob@cowsnet.com.au&&&split/[@.]/&&s&.com.&_&&&print'