(You are Anonymous)

Added | Removed | Changed | Unmodified

Revision 11 Current
= Setting Drop Down Menu Values in CGI::Application projects   = Setting Drop Down Menu Values in CGI::Application projects  
   
Originally compiled by Steve Comrie, September 11th, 2003.   Originally compiled by Steve Comrie, September 11th, 2003.  
Editted significantly by MarkStosberg   Editted significantly by MarkStosberg  
   
/What's the best way to create a <select> form element using CGI::Application?/   /What's the best way to create a <select> form element using CGI::Application?/  
   
== General Discussion   == General Discussion  
   
/This is taken from Sam Tregar's HTML::Template FAQ/   /This is taken from Sam Tregar's HTML::Template FAQ/  
   
There is much disagreement on this issue. My personal preference is to use   There is much disagreement on this issue. My personal preference is to use  
CGI.pm's excellent popup_menu() and scrolling_list() functions to fill in a   CGI.pm's excellent popup_menu() and scrolling_list() functions to fill in a  
single <tmpl_var select_foo> variable.   single <tmpl_var select_foo> variable.  
   
To some people this smacks of mixing HTML and code in a way that they hoped   To some people this smacks of mixing HTML and code in a way that they hoped  
HTML::Template would help them avoid. To them I'd say that HTML is a violation   HTML::Template would help them avoid. To them I'd say that HTML is a violation  
of the principle of separating design from programming. There's no clear   of the principle of separating design from programming. There's no clear  
separation between the programmatic elements of the <form> tags and the layout   separation between the programmatic elements of the <form> tags and the layout  
of the <form> tags. You'll have to draw the line somewhere - clearly the   of the <form> tags. You'll have to draw the line somewhere - clearly the  
designer can't be entirely in charge of form creation.   designer can't be entirely in charge of form creation.  
   
It's a balancing act and you have to weigh the pros and cons on each side. It   It's a balancing act and you have to weigh the pros and cons on each side. It  
is certainly possible to produce a <select> element entirely inside the   is certainly possible to produce a <select> element entirely inside the  
template. What you end up with is a rat's nest of loops and conditionals.   template. What you end up with is a rat's nest of loops and conditionals.  
Alternately you can give up a certain amount of flexibility in return for   Alternately you can give up a certain amount of flexibility in return for  
vastly simplifying your templates. I generally choose the latter.   vastly simplifying your templates. I generally choose the latter.  
   
Another option is to investigate HTMLFillInForm which some have reported   Another option is to investigate HTMLFillInForm which some have reported  
success using to solve this problem.   success using to solve this problem.  
   
== CGI.pm popup_menu() basics   == CGI.pm popup_menu() basics  
   
Here's an example of creating a <select> tag using CGI.pm's popup_menu, with the data provided from a database:   Here's an example of creating a <select> tag using CGI.pm's popup_menu, with the data provided from a database:  
   
my %types = @{   my %types = @{  
$DBH->selectcol_arrayref(   $DBH->selectcol_arrayref(  
"SELECT type_id,pretty_name FROM types "   "SELECT type_id,pretty_name FROM types "  
,{ Columns=>[1,2]})};   ,{ Columns=>[1,2]})};  
   
# $t is an existing HTML::Template object   # $t is an existing HTML::Template object  
# $self is a CGI::App object   # $self is a CGI::App object  
$t->param( type_popup=> $self->query->popup_menu(   $t->param( type_popup=> $self->query->popup_menu(  
-name=>'type_id',   -name=>'type_id',  
# Sort by the values rather than the keys   # Sort by the values rather than the keys  
-values=>[sort { $types{$a} cmp $types{$b} } keys %types],   -values=>[sort { $types{$a} cmp $types{$b} } keys %types],  
-labels=>\%types,   -labels=>\%types,  
),   ),  
   
== HTML::!FillInForm basics   == HTML::!FillInForm basics  
   
The HTMLFillInForm module takes an existing HTML form and fills   The HTMLFillInForm module takes an existing HTML form and fills  
it in with data you provide as a perl data structure, returning the merged document.   it in with data you provide as a perl data structure, returning the merged document.  
   
{pod:HTML::FillInForm} has a simple interface and works well for just about any   {pod:HTML::FillInForm} has a simple interface and works well for just about any  
HTML form-filling job. If your form is generated dynamically, just pass the   HTML form-filling job. If your form is generated dynamically, just pass the  
generated form through your templating system before sending it to the browser.   generated form through your templating system before sending it to the browser.  
   
Besides delivering an easy solution to populate <select> tags, HTML::!FillInForm is handy   Besides delivering an easy solution to populate <select> tags, HTML::!FillInForm is handy  
for developing "update" forms. Without it, you might need to add extra template tokens   for developing "update" forms. Without it, you might need to add extra template tokens  
for every field, like this:   for every field, like this:  
   
<input type="text" name="color" value="<!-- tmpl_var name="color" -->">   <input type="text" name="color" value="<!-- tmpl_var name="color" -->">  
   
With HTML::!FillInForm, you skip adding all these tags because it will take care   With HTML::!FillInForm, you skip adding all these tags because it will take care  
of filling in the form for you. Just the basic tag declaration is sufficient:   of filling in the form for you. Just the basic tag declaration is sufficient:  
   
<input type="text" name="color">   <input type="text" name="color">  
   
Removing the need for this extra code removes a potential source of bugs.   Removing the need for this extra code removes a potential source of bugs.  
   
Here's an example of using {pod:CGI::Application::Plugin::FillInForm} to populate an "update" form for an application:   Here's an example of using {pod:CGI::Application::Plugin::FillInForm} to populate an "update" form for an application:  
   
my $item= $DBH->selectrow_hashref("SELECT *   my $item= $DBH->selectrow_hashref("SELECT *  
FROM dealers where dealer_id = ?",{},$FORM{dealer_id});   FROM dealers where dealer_id = ?",{},$FORM{dealer_id});  
   
my $t = $self->load_tmpl('admin-content-edit.html');   my $t = $self->load_tmpl('admin-content-edit.html');  
$t->param($item);   $t->param($item);  
   
# This use line could be safely put in a base class, since   # This use line could be safely put in a base class, since  
# it only loads HTML::FillInForm as needed   # it only loads HTML::FillInForm as needed  
use CGI::Application::Plugin::FillInForm qw/fill_form/;   use CGI::Application::Plugin::FillInForm qw/fill_form/;  
return $self->fill_form(\$t->output,$item);   return $self->fill_form(\$t->output,$item);  
   
{pod:CGI::Application::ValidateRM} uses HTML::!FillInForm to display a form reloaded with the original input intact, plus   {pod:CGI::Application::ValidateRM} uses HTML::!FillInForm to display a form reloaded with the original input intact, plus  
additional error messages diplayed.   additional error messages diplayed.  
   
The following CGI::App mailing list members have also recommened   The following CGI::App mailing list members have also recommened  
HTML::FillInForm: SteveComrie, MarkStosberg, Brett Sanger, Cess Hek, JasonPurdy   HTML::FillInForm: SteveComrie, MarkStosberg, Brett Sanger, Cess Hek, JasonPurdy  
   
== Alternative: Just make the first item dynamic   == Alternative: Just make the first item dynamic  
   
Here's an alternative that is spotted less in the wild on the Web:   Here's an alternative that is spotted less in the wild on the Web:  
   
You can make just the first item on the list dynamic. This does mean   You can make just the first item on the list dynamic. This does mean  
that the default is listed twice: (once at the top and once in the list).   that the default is listed twice: (once at the top and once in the list).  
In some cases this may be confusing to users. To other users, however,   In some cases this may be confusing to users. To other users, however,  
having the current value repeated at the top instead of hidden among all   having the current value repeated at the top instead of hidden among all  
the other options, may even be an added value.   the other options, may even be an added value.  
   
You can visually separate this with a line.   You can visually separate this with a line.  
   
<select name=episode>   <select name=episode>  
<tmpl_if episode/value>   <tmpl_if episode/value>  
<option value="<tmpl_var episode/value>"><tmpl_var episode/name></option>   <option value="<tmpl_var episode/value>"><tmpl_var episode/name></option>  
<option disabled>---------</option>   <option disabled>---------</option>  
</tmpl_if>   </tmpl_if>  
<option value="1">Episode I</option>   <option value="1">Episode I</option>  
<option value="2">Episode II</option>   <option value="2">Episode II</option>  
<option value="3">Episode III</option>   <option value="3">Episode III</option>  
<option value="4">Episode IV</option>   <option value="4">Episode IV</option>  
</select>   </select>  
   
== Alternative: Roll your own   == Alternative: Roll your own  
   
Jeff !MacDonald provided this example of building your own select tag from scratch.   Jeff !MacDonald provided this example of building your own select tag from scratch.  
This technique allows you to have a little more HTML in your template rather than generated by CGI.pm.   This technique allows you to have a little more HTML in your template rather than generated by CGI.pm.  
   
$sql = "SELECT id, name, CASE WHEN id = 123 THEN 'SELECTED' END AS selected FROM sometable";   $sql = "SELECT id, name, CASE WHEN id = 123 THEN 'SELECTED' END AS selected FROM sometable";  
   
$prepare/execute/yada yada   $prepare/execute/yada yada  
$tmp->param(LIST => $sth->fetchall_arrayref({}));   $tmp->param(LIST => $sth->fetchall_arrayref({}));  
   
Where LIST is a list in HTML::Template format in the template. that might look like this.   Where LIST is a list in HTML::Template format in the template. that might look like this.  
   
<select>   <select>  
<TMPL_LOOP NAME=OPEN_LIST>   <TMPL_LOOP NAME=OPEN_LIST>  
<option value="<TMPL_VAR NAME=id>" <TMPL_VAR NAME=selected>><TMPL_VAR NAME=name></option>   <option value="<TMPL_VAR NAME=id>" <TMPL_VAR NAME=selected>><TMPL_VAR NAME=name></option>  
</TMPL_LOOP>   </TMPL_LOOP>  
</select>   </select>  
   
== Comments   == Comments  
   
If you really want to have some fun, try defining your forms using a .xml file and then using XML::Simple to read the file into a hash and pass it to HTML::Template, then store user feedback in a separate .xml file, get XML::Simple to read that file into a hash and pass it to HTML::FillInForm .. then output the template with the form filled in. On the other end write the saved .xml file using the contents of $cgi->Vars and you've got an instant dynamic form reading from a master .xml template and store all user records in individual .xml files that can be editing simply.   If you really want to have some fun, try defining your forms using a .xml file and then using XML::Simple to read the file into a hash and pass it to HTML::Template, then store user feedback in a separate .xml file, get XML::Simple to read that file into a hash and pass it to HTML::FillInForm .. then output the template with the form filled in. On the other end write the saved .xml file using the contents of $cgi->Vars and you've got an instant dynamic form reading from a master .xml template and store all user records in individual .xml files that can be editing simply.  
   
Sorry for the run on sentence.   Sorry for the run on sentence.  
   
-- SteveComrie   -- SteveComrie  
   
== Using Template Toolkit's CGI Plugin   == Using Template Toolkit's CGI Plugin  
   
If you're using Template Toolkit instead of HTML::Template (as I believe you should), then you can use the CGI plugin (Template::Plugin::CGI) in your templates to build HTML form elements in your templates. This allows you to pass just the data to the template instead of the full HTML of the controls. This both maintains the separation of logic and data and also makes your templates more readable.   If you're using Template Toolkit instead of HTML::Template (as I believe you should), then you can use the CGI plugin (Template::Plugin::CGI) in your templates to build HTML form elements in your templates. This allows you to pass just the data to the template instead of the full HTML of the controls. This both maintains the separation of logic and data and also makes your templates more readable.  
   
In the context of a Template Toolkit template, first you import the CGI plugn:   In the context of a Template Toolkit template, first you import the CGI plugn:  
   
[% USE CGI %]   [% USE CGI %]  
   
And later, having passed in an array ref containing values (state_values) and a hash ref providing the labels (state_labels), you'd do this:   And later, having passed in an array ref containing values (state_values) and a hash ref providing the labels (state_labels), you'd do this:  
   
State: [% CGI.popup_menu(name => 'state',   State: [% CGI.popup_menu(name => 'state',  
id => 'state',   id => 'state',  
values => state_values,   values => state_values,  
labels => state_labels,) %]   labels => state_labels,) %]  
-- BergBrains   -- BergBrains  
   
== See Also   == See Also  
   
* [Plugins]   * [Plugins https://github.com/markstos/CGI--Application/wiki/Plugins]  
* HTMLFillInForm   * HTMLFillInForm