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

Esteemed Monks, I seek your wisdom and forbearance = this code happily loads CGI params into my namespace, and if desired can fill an array with 0, 1 or many elements:
package Begin_CGI; use CGI; sub import { # ====== my( $r_params ) = (@_) ; my $namespace = (caller)[0] ; use vars qw(@params) ; if ( defined($r_params ) ) { @params = @{$r_params || [] } ; foreach my $var ( '@params', @params ) { my $name = substr($var,1) ; *{"${namespace}::${name}"} = ( substr($var,0,1) eq '@' ) ? \@{$name} : \${$name} ; } } ; ETC,ETC #CGI script... use Begin_CGI ( [qw($scalarparam @arrayparam)]; print start_form(-name=>"input_form") . textfield(-name=>"arrayparam", -value=>"$array_param[0]" -force= +>1); #zero, one or more text fields if so desired print hidden(-name=>"arrayparam", -value=>"dummy", -force=>1) if is_IE +(); print end_form ; #HTML/Javascript <BODY onload="="window_loaded()"> <SCRIPT> function window_loaded { ensure_array(window.document.input_form, 'arrayparam'); } function ensure_array( this_form, name ){ // ------------ // Ensures that the specified array to hold form elements exists. // This function is needed because browser(s) only automaticaly create +s an array // when there is more than one form element with the same name. // This function works around the problem as follows (Netscape): // If there are no form elements with its name it creates an empty arr +ay. // If there is a single element with its name that is the first array +element. // If the array already existed it is returned. // This function works around the problem as follows (IE 6.0): // A dummy (hidden) form element is generated by the perl script // Dummy has disabled property set to true by this function // Perl script strips dummy elements prior to processing // Iterations over arrays that contain dummy elements use adj_len to r +educe length by one if IE var form_prop = "this_form." + name ; var obj = eval( form_prop ) ; if( browser_type() == 'isIE' ) { for ( i=obj.length-1; i >= 0; i-- ) { if( obj[i].value == 'dummy' ) { obj[i].disabled = true ; } } } else if( browser_type() == 'isNav' ) { if ( obj == undefined ) { eval("delete " + form_prop) ; eval(form_prop + " = new Array(0)") ; } else { select_obj = false; if( obj.type != undefined ) { select_obj = ( obj.type.indexOf( "select-" ) == 0 ); } if ( obj.length == undefined || select_obj ) { a = new Array(obj) ; eval("delete " + form_prop) ; eval(form_prop + " = a") ; } } } } </SCRIPT>
I seek your wisdom to help deliver me from the ugliness of this code: But... the main (only?) thing that this code has going for it is that it works with only minor tweaks to the existing Javascript. This is after a lot of experimentation - so please only propose improvements that actually work!!! Lastly, I pray for your forbearance - surely the ration of perl to js in this question is sullying the monastery. Please help me crush it back to a couple of lines!!!

Replies are listed 'Best First'.
Re: CGI Ensure Array
by vladb (Vicar) on May 30, 2002 at 16:19 UTC
    You say...

    // Ensures that the specified array to hold form elements exists. // This function is needed because browser(s) only automaticaly creates an array // when there is more than one form element with the same name.

    I had similar problem with one of my CGI scripts where I had to deal with multiple drop down and radio boxes. The way I was able to make sure that my CGI would always get an array of elements is by simply inserting a hidden form element with the same name. In addition, I also marked a single selection (in the select box) as default. For example, if you had a select field 'foo_choices', you'd need to add this hidden field:

    <form ... > <input type="hidden" name="foo_choices"> Make a foo choice: <select name="foo"> <option > ... <!--- leave one option pre-selected by default... ---> </select> </form>
    So, when the form is submitted, you'll always have at least two instances of the 'foo_choices' parameter sent to your CGI. The CGI module, seeing this, will build an array. Frankly, I didn't have to resort to complex JS scripts to make this work.

    I hope this helps somewhat in your noble effort to reduce the JS rubbish and leave more to Perl! ;-)

    _____________________
    $"=q;grep;;$,=q"grep";for(`find . -name ".saves*~"`){s;$/;;;/(.*-(\d+) +-.*)$/; $_=["ps -e -o pid | "," $2 | "," -v "," "];`@$_`?{print"+ $1"}:{print" +- $1"}&&`rm $1`; print$\;}
Re: CGI Ensure Array
by thpfft (Chaplain) on May 30, 2002 at 17:45 UTC

    Well, your main question is nice and easy, and nearly all that complexity can go. CGI.pm will return input parameters as an array if asked for them in array context, however many there are. So:

    use CGI; my $input = new CGI; my @var = $input->param('var');

    should work without your having to pad the form or check the browser type. tests with:

    use CGI; use Data::Dumper; my $input = new CGI; my @var = $input->param('var'); print "Content-type:text/plain\n\n"; print Dumper \@var;

    seem to confirm that it works. But anyway, if you _really_ want to load the input into a namespace (why?), you don't have to go through all those hoops to do it:

    my $query = new CGI; $query->import_names('input');

    will import the entire parameter set into an input:: namespace, and you can then just ask for @input::arrayparam to get values in array form. But you lose a lot of power this way: it's hard to iterate over the set of input parameters, for example. I would suggest using the object-oriented interface to CGI instead, if you can, and passing around the CGI object if necessary. It's safer, more flexible and more friendly to later development than this approach, which seems very vulnerable to me.

    But i confess i'm slightly baffled by the javascript part - can't see what it's doing for you - so perhaps am up wrong tree entirely?