My first posted code snippet. Sorry if I leave anythign out, include anything extraneous, etc.

This snippet will generate the Javascript for 2 popup menus, the 2nd of which has varying options depending on the value of the first. The form in this example is named 'your_form', the first popup_menu is named 'category' and the second is named 'subcategory'. The %categories hash should have keys thats are the categories and values that are arrays of subcategories.

I tried to make it as neat as possible. It was formatted in an editor with an 80-character width.

UPDATE: Made some changes suggested by davidrw

# Sample categories hash, courtesy of davidrw my %categories = ( A => [ 'B', 'Z' ], C => ['D', 'E'] ); my $category = param('category') || ''; my $subcategory = param('subcategory') || ''; # Generate javascript print <<EOF; <script language="javascript"> function catChange(newCat) { with(document.your_form.subcategory) { options.length=0; switch(newCat) { EOF foreach $c (keys %categories) { print <<EOF; case "$c": EOF my $i = 0; foreach my $s (@{$categories{$c}}) { # Keeps menu options when page reloads # Only matters when form target is the script itself my $opts_params = ($s eq $subcategory && $c eq $category) ? ',true,true' : ''; print <<EOF; options[$i]=new Option("$s" $opts_params); EOF ++$i; } print "break;\n"; } print <<EOF; break; EOF } print <<EOF; case "Category": options[0]=new Option("Please choose a category"); break; } } } </script> EOF # Well, now wasn't that fun?! # Beginning of form print start_form(-name=>'your_form'); print p(popup_menu(-name=>'category', -values=>['Category',sort keys %categories], -onChange=> 'catChange(this.options[this.selectedIndex].val +ue);'), popup_menu(-name=>'subcategory', -values=>['Please choose a category']));

Replies are listed 'Best First'.
Re: Double popup_menu
by davidrw (Prior) on Aug 10, 2005 at 13:09 UTC
    I tried to make it as neat as possible.
    Go for here-documents (perldoc perldata) to reduce the clutter of the single quotes and concatentations and double-quoted newlines:
    use strict; use warnings; my %categories = ( A => [ 'B', 'Z' ], C => ['D', 'E'] ); my $category = param('category') || ''; my $subcategory = param('subcategory') || ''; use CGI qw/:standard/;; # Generate javascript print <<EOF; <script language="javascript"> function catChange(newCat) { with(document.your_form.subcategory) { options.length=0; switch(newCat) { EOF foreach my $c (keys %categories) { print <<EOF; case "$c": EOF my $i = 0; foreach my $s (@{$categories{$c}}) { my $opts_params = ($s eq $subcategory && $c eq $category) ? ',true,true' : ''; print <<EOF; options[$i]=new Option("$s" $opts_params ); EOF ++$i; } print <<EOF; break; EOF } print <<EOF; case "Category": options[0]=new Option("Please choose a category"); break; } } } </script> EOF # Well, now wasn't that fun?! # Beginning of form print start_form(-name=>'your_form'); print p(popup_menu(-name=>'category', -values=>['Category',sort keys %categories], -onChange=> 'catChange(this.options[this.selectedIndex].val +ue);'), popup_menu(-name=>'subcategory', -values=>['Please choose a category']));
    Also, i did the following:
    • locally scoped $c and $s since they're only used in the foreach loops
    • added the 'use CGI qw/:standard/' line so that readers know it's required
    • declared $category and $subcategory vars and initialized them to the param() call, but default to '' to avoid unitialized value warnings during the eq string comparison.
    Another good way to tidy up the print statements besides here-documents is printf -- for example:
    printf 'options[%d]=new Option("%s" %s );\n', $i, $s, $opts_params;
    And of course there is always Template Toolkit or HTML::Template and others, but that's probably overkill in this case.

      I of course bow to your wisdom. I forgot about here-documents and printf because I don't use them (have never had a script for which they were appropriate before). Your solution is much neater. I didn't include any use lines because it is a snippet, rather than a fully functioning program, although I understand your desire to include them.

      I'll make your suggested adjustments above (and in my script). Thanks! $[id://davidrw]++