impossiblerobot has asked for the wisdom of the Perl Monks concerning the following question:
Since I generally prefer my HTML to look like HTML, I tend to use templates and here-docs, and eschew CGI.pm's HTML-generation features.
However, on my current project, I think these features could be useful -- if I can figure out how to do what I need to do. :-)
A fairly common feature in forms/surveys is a radio-select with an "Other" option, and a text field attached to the "Other" option, as follows:
What is your favorite number?<br>
<input type="radio" name="question" value="a">5</input><br>
<input type="radio" name="question" value="b">7</input><br>
<input type="radio" name="question" value="c">13</input><br>
<input type="radio" name="question" value="d">Other (please specify:)<
+/input> <input type="text" name="other"><br>
I need to be able to optionally add (for example) a text field to any of the radio options. Does anyone know of a clean way to do this with CGI.pm, or am I better off writing my own HTML-generation routine?
Impossible Robot
(jeffa) Re: Creating HTML radio button group with text field
by jeffa (Bishop) on May 05, 2002 at 01:38 UTC
|
Other then omitting the <br> tag in between the last
radio box and the text box, this should do the
trick get you started.
Personally, i would use HTML::Template instead.
This is some hairy code :P
use strict;
use CGI qw(:standard);
use CGI::Pretty;
my @question = ('a'..'d');
my $answer = [
[('number',5,7,13)],
[('color','red','green','fuschia')],
];
print header, start_html, start_form;
foreach my $i (0..$#$answer) {
# remove type of question from front and add 'Other' to end
my $thingy = shift @{$answer->[$i]};
push @{$answer->[$i]}, 'Other (please specify)';
print "What is your favorite $thingy?", br,
radio_group(
-name => sprintf('%s%02d','question',$i + 1),
-labels => {
map {
$question[$_] => $answer->[$i]->[$_]
} (0..$#question)},
-values => \@question,
-linebreak => 'true',
),
textfield(sprintf('%s%02d','other',$i + 1)), p;
}
print submit, end_form, end_html;
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)
| [reply] [d/l] |
|
Thanks, jeffa, but this doesn't quite meet my requirements. I'm sorry if my question wasn't clear. As I said in my original post (but did not include in my HTML sample):
I need to be able to optionally add (for example) a text field to any of the radio options.
Here's another example to clarify:
Where did you hear about this product?
<input type="radio" name="question" value="a">Friend</input><br>
<input type="radio" name="question" value="b">Magazine (please specify
+:)</input> <input type="text" name="magname"><br>
<input type="radio" name="question" value="c">Brochure</input><br>
<input type="radio" name="question" value="d">Other (please specify:)<
+/input> <input type="text" name="other"><br>
I hope this makes it clearer what I want to be able to do.
Impossible Robot | [reply] [d/l] |
|
Sorry impossiblerobot - i indeed did miss that
rather clear requirement. How about a cleaner HTML::Template solution?
use strict;
use CGI qw(header);
use HTML::Template;
my $data = do {local $/; <DATA>};
my $template = HTML::Template->new(
scalarref => \$data,
);
$template->param(
questions => [
{
question => 'What is your favorite number?',
radio => [
{
regular => 'question01',
value => 'a',
label => 5,
},
{
regular => 'question01',
value => 'b',
label => 7,
},
{
regular => 'question01',
value => 'c',
label => 13,
},
{
special => 'question01',
value => 'd',
label => 'Other',
text => 'other',
},
],
},
{
question => 'Where did you hear about this product?',
radio => [
{
regular => 'question02',
value => 'a',
label => 'Friend',
},
{
special => 'question02',
value => 'b',
label => 'Magazine',
text => 'magname',
},
{
regular => 'question02',
value => 'c',
label => 'Brochure',
},
{
special => 'question02',
value => 'd',
label => 'Other',
text => 'other',
},
],
},
],
);
print header, $template->output;
__DATA__
<form>
<tmpl_loop questions>
<p>
<tmpl_var question><br/>
<tmpl_loop radio>
<tmpl_unless special>
<input type="radio" name="<tmpl_var regular>" value="<tmpl_va
+r value>"/><tmpl_var label><br/>
<tmpl_else>
<input type="radio" name="<tmpl_var special>" value="<tmpl_va
+r value>"/><tmpl_var label> (please specify:)
<input type="text" name="<tmpl_var text>"/><br/>
</tmpl_unless>
</tmpl_loop>
</p>
</tmpl_loop>
<input type="submit">
</form>
Now for the fun part - getting the right values out! You
might want to prefix each text box with the letter and
call them all 'other'. For example, instead of calling
the Magazine textbox 'magname', call it something along the
lines of 'b-other' so you can dynamical retrieve it from
CGI::param(). This is just off the top of my head
(/me winks at BUU), but you get the point. Good luck!
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)
| [reply] [d/l] |
|
(podmaster) Re: Creating HTML radio button group with text field
by PodMaster (Abbot) on May 05, 2002 at 01:58 UTC
|
Straight from the guts of CGI.pm, where you should've had at least one visit ;)
#### Method: radio_group
# Create a list of logically-linked radio buttons.
# Parameters:
# $name -> Common name for all the buttons.
# $values -> A pointer to a regular array containing the
# values for each button in the group.
# $default -> (optional) Value of the button to turn on by default.
+ Pass '-'
# to turn _nothing_ on.
# $linebreak -> (optional) Set to true to place linebreaks
# between the buttons.
# $labels -> (optional)
# A pointer to an associative array of labels to print nex
+t to each checkbox
# in the form $label{'value'}="Long explanatory label".
# Otherwise the provided values are used as the labels.
# Returns:
# An ARRAY containing a series of <INPUT TYPE="radio"> fields
####
'radio_group' => <<'END_OF_FUNC',
sub radio_group {
my($self,@p) = self_or_default(@_);
my($name,$values,$default,$linebreak,$labels,
$rows,$columns,$rowheaders,$colheaders,$override,$nolabels,@oth
+er) =
rearrange([NAME,[VALUES,VALUE],DEFAULT,LINEBREAK,LABELS,
ROWS,[COLUMNS,COLS],
ROWHEADERS,COLHEADERS,
[OVERRIDE,FORCE],NOLABELS],@p);
my($result,$checked);
if (!$override && defined($self->param($name))) {
$checked = $self->param($name);
} else {
$checked = $default;
}
my(@elements,@values);
@values = $self->_set_values_and_labels($values,\$labels,$name);
# If no check array is specified, check the first by default
$checked = $values[0] unless defined($checked) && $checked ne '';
$name=$self->escapeHTML($name);
my($other) = @other ? " @other" : '';
foreach (@values) {
my($checkit) = $checked eq $_ ? qq/ checked="checked"/ : '';
my($break);
if ($linebreak) {
$break = $XHTML ? "<br />" : "<br>";
}
else {
$break = '';
}
my($label)='';
unless (defined($nolabels) && $nolabels) {
$label = $_;
$label = $labels->{$_} if defined($labels) && defined($labels-
+>{$_});
$label = $self->escapeHTML($label,1);
}
$_=$self->escapeHTML($_);
push(@elements,$XHTML ? qq(<input type="radio" name="$name" value=
+"$_"$checkit$other />${label}${break})
: qq/<input type="radio" name="$name" va
+lue="$_"$checkit$other>${label}${break}/);
}
$self->register_parameter($name);
return wantarray ? @elements : join(' ',@elements)
unless defined($columns) || defined($rows);
return _tableize($rows,$columns,$rowheaders,$colheaders,@elements)
+;
}
END_OF_FUNC
perl -MData::Dumper -MCGI=:all -e"print Dumper radio_group('IamGroup',
+[qw/one othe
r/],'one','linebreaks');"
perl -MCGI=all -e"print textfield('other')"
Now what I'm wondering is how is it that you didn't happen to stumble accross the CGI documentation, or even its guts?
P.S. -- here's a few *secret* links, don't tell nobody (
CGI,
How to RTFM,
http://ovid.perlmonk.org,
http://stein.cshl.org/,
perlsec)
update:
Whaza?
1) No the CGI documentation does not explicitly state how you can do what you want (you're doing some odd things, and it'd be crazy for the documentation to reflect that).
2) Nooooo, If you don't know how to use certain functions, or they're not documented to your satisfaction, just crack open CGI.pm (and yeah, you could borrow, but that wasn't my point)
3) Didn't mean to imply you should modify CGI.pm
Yes, you missed my point completely (I guess I should've been more explicit, kinda like jeffa up there).
I just wanted to point out to you, radio_group (which returns a list) and textfield, two CGI.pm functions, which *you* can use to solve your problem. You have to use your imagination as to how to do it (i ain't writing code like jeffa, ain't got time)
Hopefully that clarifies it (if not, update your reply).
Look ma', I'm on CPAN.
** The Third rule of perl club is a statement of fact: pod is sexy. | [reply] [d/l] [select] |
|
| [reply] |
Re: Creating HTML radio button group with text field
by Popcorn Dave (Abbot) on May 05, 2002 at 01:25 UTC
|
I ran in to a similar ( I think :] ) problem on a script I was doing for an HTML page that would allow the user to update items for sale, and delete them when they were sold.
Since I had checkboxes, I needed a way to make them unique. I ended up doing generation on the fly manually. There was no way for CGI.pm to do it as I was basically saying 'd'.$index, and I was incrementing index for every item in the base file.
So in answer to your question, if you need it to be on the fly, you're probably going to have to do it by hand. It makes your not quite as clean as CGI.pm is going to make it look, but them's the breaks :)
Hope that helps you out. | [reply] |
Re: Creating HTML radio button group with text field
by impossiblerobot (Deacon) on May 05, 2002 at 15:07 UTC
|
Here was my CGI.pm solution (with less relevant details stripped out):
my @values = qw(
a b c d
);
my %labels = (
a => 'Friend',
b => 'Magazine (please specify:)',
c => 'Internet',
d => 'Other',
);
$labels{$_} = $cgi->escapeHTML($labels{$_}) for keys %labels;
$labels{b} .= $cgi->textfield(-name => 'magname');
print $cgi->start_form();
$cgi->autoEscape(0);
print $cgi->radio_group(-name => 'question',
-values => \@values,
-linebreak => 'true',
-labels => \%labels);
$cgi->autoEscape(1);
print $cgi->endform;
I didn't like having to turn off autoEscape() and explicitly escape the other entries, so I was looking for a cleaner solution -- but it looks like that's as good as it gets (with CGI.pm, at least).
Thanks jeffa, podmaster.
Impossible Robot | [reply] [d/l] |
|
| [reply] |
|
|