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

Hallo, I have the following perl script which through cgi prints a text box, among other things, and lets me do a keyword search in a mysql database. I was wondering if there is a way to add a button that will replicate the code for again so I can search for two,three, and so on parameters. The code is as follows :
my $i = 0; while (@col = $sth->fetchrow()) { $i++; print "<INPUT TYPE=\"checkbox\" NAME=\"tissues\" VALUE=\"$col[ +0]\">$col[0];\n"; } $sth->finish; print "<br>"; print "The mirna expression level should be: <br>\n"; print "Greater than :<INPUT TYPE=\"TEXT\" NAME=\"greater\"<br>\n"; print "Lower than :<INPUT TYPE=\"TEXT\" NAME=\"lower\"<br>\n"; print "<INPUT TYPE=\"checkbox\" NAME=\"hsa_mirna\" VALUE=\"hsa-mir +-\">hsa-mir-\n"; print "OR\n"; print "<INPUT TYPE=\"checkbox\" NAME=\"block\" VALUE=\"block\">blo +ck\n"; print "<INPUT TYPE =\"textbox\" NAME=\"number\"\n"; print '<INPUT TYPE = SUBMIT VALUE="Click To Submit">'; print '<INPUT TYPE=RESET></FORM>'; print '</body></html>';
the part that I really want to replicate is the textbox element. Is there any way to do that in perl, or should I try to find something in javascript? thank you in advance for any help

Replies are listed 'Best First'.
Re: replicating blocks of code in perl and cgi
by almut (Canon) on May 26, 2010 at 09:54 UTC

    There are generally two approaches: (1) do it server-side, (2) do it client-side in Javascript, by having the button call a routine that manipulates the DOM of the page to add another textbox element to the form.

    I'll outline variant 1, as it can be done in Perl. Generally, you'd need a loop around the section that outputs the HTML for the textbox. The loop count would be incremented via the add button. As HTTP is stateless, you'll have to manage persistence somehow, for example by keeping the current count value in a hidden form field, or by storing it in a session.  Of course, this variant would mean a roundtrip to the server (plus recreating the entire page with the current form values) every time you add another textbox — which could be avoided using the Javascript variant, at the cost of requiring people to have JS enabled.

Re: replicating blocks of code in perl and cgi
by ambrus (Abbot) on May 26, 2010 at 21:26 UTC

    This is actually a good question, because some other people might ask this too in the future. I've actually written some similar code recently, so I'll try to make a standalone example from it.

    The following is a form with a single repeatable text input field. It works better in some browsers, but the form is still usable from any browser (even without javascript or css).

    You can currently view this example live at http://russell2.math.bme.hu/~ambrus/pu/cpdemo/cpdemo.cgi.

    Below is the executable code of the CGI, which you should call cpdemo.cgi.

    #!/usr/local/bin/perl -T # Standalone demo for repeatable html input field. use warnings; use strict; use CGI; sub escapeHTML { my($v) = @_; $v =~ s/&/&amp;/g; $v =~ s/</&lt;/g; $v =~ s/>/&gt;/g; $v =~ s/"/&quot;/g; $v; } our(@nam); our $ownurl = "cpdemo.cgi"; sub hparm { @nam = grep { length } CGI::param("fld-nam"); } sub htop { print qq{Content-Type: text/html; charset=utf-8\n}, qq{\n}, qq{<!doctype html public "-//W3C//DTD HTML 4.01//EN" "http://w +ww.w3.org/TR/html4/strict.dtd">\n}, qq{<html>\n}, q{ <head> <meta http-equiv="content-type" content="text/html; charset=ut +f-8"> <title>Repeatable html input field demo</title> <link rel="stylesheet" href="cpdemo.css" type="text/css"> <link id="style_js" rel="alternate stylesheet" disabled href=" +cpdemojs.css" type="text/css" title="style_js"> <script type="text/javascript" src="cpdemo.js"></script> </head> <body> <h1> Repeatable html input field demo </h1> }; # note: do not add a title attribute to the first style sheet but +do not delete the one from the second stylesheet or this breaks in ko +nqueror } sub hform { print q{ <p><a href="} . $ownurl . q{">Clear form</a> <form action="} . $ownurl . q{" method="POST" accept-charset=" +utf-8"> }; my $nrepeat = CGI::param("rep-nam"); $nrepeat = $nrepeat ? int($nrepeat) : 1; defined(CGI::param("add-nam")) and $nrepeat++; $nrepeat < @nam and $nrepeat = @nam; 1 <= $nrepeat or $nrepeat = 1; $nrepeat <= 1022 or $nrepeat = 1022; my @val = @nam; for my $krepeat (0 .. $nrepeat + 0) { print qq{ <div }; if ($nrepeat == $krepeat) { print qq{ class="form_addtemplate" id="addtpl-nam"}; } print qq{ > <p>Name: <input type="text" name="fld-nam" size="60" value="}, escapeHTML(@val ? shift @val : ""), qq{"> <span class="form_tailloc"> }; if ($nrepeat - 1 == $krepeat) { print qq{ <span class="form_tail" id="tail-nam"> <a class="form_addlink" href="javascript:void\(addanot +her\(&quot;nam&quot;\)\)">Add another</a> </span> }; } print q{</span>}; if ($nrepeat == $krepeat) { print qq{ <small class="form_addusage"> (Too add one more such field, fill all of them and pre +ss preview.) </small> }; } print q{</div>}; # addtpl } print q{<input type=hidden name="rep-nam" value="} . $nrepeat . qq{" +>\n}; print qq{ <p> <input name="preview" type="submit" value="Preview" class="for +m_submitbutton"> </form> }; } sub hout { print q{<p><textarea class="out_curtext" rows="8" cols="70">}; for my $val (@nam) { print escapeHTML($val) . "\n"; } print qq{</textarea>\n}; } sub hbot { print qq{</body></html>\n}; } sub hmain { ${^TAINT} or die "run in taint mode (perl -T) please"; hparm; htop; hform; hout; hbot; } hmain; 1; __END__

    It needs three more files for support. The first one is cpdemo.js

    /* Standalone demo for repeatable html input field: javascript. */ function addanother(fld) { // vvv first part should work in any browser var tpl = document.getElementById("addtpl-" + fld); var cpy = tpl.cloneNode(true); cpy.id = ""; cpy.className = ""; tpl.parentNode.insertBefore(cpy, tpl); // vvv second part only works in some browsers, but the form still + works without it var tlo = cpy.getElementsByClassName && cpy.getElementsByClassName +("form_tailloc")[0]; var tco = document.getElementById("tail-" + fld); if (tlo && tco) tlo.appendChild(tco); }; function initcpdemo() { var ssa = document.getElementById("style_js"); ssa.disabled = false; }; initcpdemo(); /* END */

    The second is cpdemo.css

    /* Standalone demo for repeatable html input field: common css. */ .form_addlink { display: none; } /* END */

    And the third one is cpdemojs.css.

    /* Standalone demo for repeatable html input field: css used if javascrip +t is available. */ .form_addtemplate, .form_addusage { display: none; } a.form_addlink { display: inline; } /* END */

    Update: added missing right angle bracket for the div tag (thanks, W3C HTML validator).

Re: replicating blocks of code in perl and cgi
by Anonymous Monk on May 26, 2010 at 09:31 UTC
    the part that I really want to replicate is the textbox element. Is there any way to do that in perl....

    What do you mean, you can call print however many million times you want?

    CGI Programming

      sorry I didn't quite put it right, I want to print it on demand. So to have an add button, that will replicate that print command. Thanks

        Perhaps you mean you want to use Ajax to manipluate the DOM. You could easily use jQuery to add (or show hidden) elements without refreshing the page. Obviously this required a JavaScript enabled browser.