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

Hi Monks,

I'm getting strange results from a subroutine that is passed a hash of values, one of which comes from a checkbox from an online form.

The relevant html and code are as follows:

# html # Note that if the user selects the checkbox, the value is 'on' <tr><td>I'm logging in from home</td><td><input type="checkbox" name=" +place"></td></tr> # cgi use strict; use CGI qw(:cgi); use Data::Dumper; my $place = seewhatsthere( data => param('place'), field => 'Place', ); sub seewhatsthere { my %hash = @_; html_start(); print Dumper(%hash); exit(0); }
What happens is this:

CASE 1: The checkbox is unchecked

# Dumped $VAR1 = 'Place'; $VAR2 = undef; $VAR3 = 'data'; $VAR4 = 'field';
So we get

Place => undef
data => 'field'

which is strange and perhaps incorrect because I was expecting the following

data => undef
field => 'Place'

CASE 2: The checkbox is checked

# Dumped $VAR1 = 'data'; $VAR2 = 'on'; $VAR3 = 'field'; $VAR4 = 'Place';
So we get

data => 'on'
field => 'Place'

which is correct.

My question is: When the checkbox is unchecked ( i.e. CASE 1 ), why do I get the strange results? Can someone shed some light on what's going on?

Thanks :)

update

Thanks to everybody for the wonderful solutions :)

Replies are listed 'Best First'.
Re: Strange behaviour - cgi related
by duff (Parson) on Dec 16, 2003 at 04:36 UTC

    It's because you're calling param() in a list context, so for the non-existent parameter you get an empty list. It's just as if you had done

    my %hash = ( 'foo' => (), 'bar' => 'baz' ); # which is the same as ... my %hash = ( 'foo', 'bar', 'baz' );
      Thanks, duff!

      Just to clarify

      my $in = param('place'), my $place = seewhatsthere( data => $in, field => 'Place', );
      Is that correct way to pass the value from the checkbox?

        That's a way. The key is to not use param() in a list context. You can force scalar context as you have done (by assigning to a scalar) or you can use the scalar operator like so:

        my %hash = ( data => scalar param('place'), field => 'place', );
Re: Strange behaviour - cgi related
by edoc (Chaplain) on Dec 16, 2003 at 04:55 UTC

    mmm.. the ol' undef value in a hash def, eh?

    this should fix it for you...

    my $place = seewhatsthere( data => param('place') || '', field => 'Place', );

    Update: Thanks duff! (lightbulb appears mystically above J's head) ..scary how you can go in completely the wrong direction and end up where you need to be..

    cheers,

    J

      Well, it's not an undef as his code would have worked properly in the first place; it's an empty list. But yes, || is another way to force a scalar context on param() such that it does the right thing when asked to return a multi-valued parameter. In fact, I like that method quite a bit :-)

Re: Strange behaviour - cgi related
by Roger (Parson) on Dec 16, 2003 at 05:45 UTC
    I have written a module below to handle named parameters. Perhaps you will find it useful.

    package NAB::Utils::NP; use strict; use Data::Dumper; use CGI::Util qw/ rearrange /; our $Q; our $VERSION = "1.00"; sub new { my $class = shift; if (!defined $Q) { $Q = { ALIAS => caller(0) }; bless($Q, $class); } return $Q; } sub named_param { my($self, $seq, @p) = self_or_default(@_); my($s, @r) = self_or_default(@p); return rearrange($seq, @r); } sub self_or_default { my $class = $Q; if (defined $_[0] && (! ref $_[0] && ($_[0] eq ref $class || $_[0] eq $Q->{ALIAS}))) { return @_; } return @_ if (ref $_[0] eq ref $class || ref $_[0] eq $Q->{ALIAS}); unless (defined($_[0]) && (ref($_[0]) eq $class || UNIVERSAL::isa($_[0], $class))) { unshift(@_,$Q); } return wantarray ? @_ : $Q; } 1;

    And in your application -
    use strict; use warnings; use NAB::Utils::NP; my $np = NAB::Utils::NP->new; test( -option1=>undef, -option3=>'c' ); test( 'a', 'b', 'c' ); __PACKAGE__->test( -option1=>'a', -option3=>'c' ); __PACKAGE__->test( 'a', 'b', 'c' ); sub test { my($option1,$option2,$option3) = $np->named_param( [qw/ OPTION1 OPTION2 OPTION3 /], @_); print <<OPTIONS \$option1=$option1 \$option2=$option2 \$option3=$option3 OPTIONS ; }
    And the output -
    $option1= $option2= $option3=c $option1=a $option2=b $option3=c $option1=a $option2= $option3=c $option1=a $option2=b $option3=c