| 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 |