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

I have had success in the past with different uses of javascript from within a cgi script however this has stumped me. I am trying to create to list boxes with a button or link that will move the selection in one list box to the other. I have written the code in HTML and it works fine in both mozilla and IE. However when I write the exact same code in perl it doesn't work out. This is probably pretty easy for most of you but hopefully you can offer some help. First here is the HTML code that works
<html> <head> <title>TEST</title> <SCRIPT language="Javascript" type="text/javascript"> function moveOptions(from,to) { for (var i=0; i<from.options.length; i++) { var o = from.options[i]; if (o.selected) { to.options[to.options.length] = new Option( o.text, o. +value, false, false); } } for (var i=(from.options.length-1); i>=0; i--) { var o = from.options[i]; if (o.selected) { from.options[i] = null; } } from.selectedIndex = -1; to.selectedIndex = -1; } </SCRIPT> </head> <body> <form name="form" action=""> <table summary=""> <tr> <td> <select name="available" multiple size="5"> <option value="1">Admin</option> <option value="2">Test</option> <option value="3">Clients</option> </select> </td> <td> <input class="accessButton" type="button" value=">>" o +nClick="moveOptions(this.form.available, this.form.selected);"><br> <input class="accessButton" type="button" value="<<" o +nClick="moveOptions(this.form.selected, this.form.available);"> </td> <td> <select multiple name="selected" size="5"></select> </td> </tr> </table> </form> </body> </html>
Here is the perl code:
#!/usr/bin/perl use strict; use CGI qw/:standard/; #Initiate Variables #Create functions #write HTML print "Content-Type: text/html\n\n"; print "<html>\n"; print "<head>\n"; print "<title>TEST</title>\n"; print "<SCRIPT LANGUAGE=\"Javascript\" type=\"text/javascript\"> function moveOptions(from,to) { for (var i=0; i<from.options.length; i++) { var o = from.options[i]; (o.selected) { to.options[to.options.length] = new Option( o.text, o. +value, false, false); } } for (var i=(from.options.length-1); i>=0; i--) { var o = from.options[i]; if (o.selected) { from.options[i] = null; } } from.selectedIndex = -1; to.selectedIndex = -1; } </SCRIPT> "; print "</head>\n"; print "<body>\n"; print "<form name=\"form\" action=\"\">\n"; print " <table summary=\"\">\n"; print " <tr>\n"; print " <td>\n"; print " <select name=\"available\" multiple size=\"5\"> +\n"; print " <option value=\"1\">Admin</option>\n"; print " <option value=\"2\">Test</option>\n"; print " <option value=\"3\">Clients</option>\n"; print " </select>\n"; print " </td>\n"; print " <td align=\"center\">\n"; #print " <a href=\"javascript:moveOptions(document.add. +available, document.add.selected);\">Add</a><br>\n"; #print " <a href=\"javascript:moveOptions(document.add. +selected, document.add.available);\">Remove</a>\n"; print " <input class=\"accessButton\" type=\"button\" v +alue=\"Add>>\" onClick=\"moveOptions(this.form.available, this.form.s +elected;\"><br>\n"; print " <input class=\"accessButton\" type=\"button\" v +alue=\"<<Remove\" onClick=\"moveOptions(this.form.selected, this.form +.available;\">\n"; print " </td>\n"; print " <td>\n"; print " <select multiple name=\"selected\" size=\"5\">< +/select>\n"; print " </td>\n"; print " </tr>\n"; print " </table>\n"; print "</form>\n"; print "</body>\n"; print "</html>\n";
Any help is greatly appreciated and if you could include a small explanation of why this is happening so I can learn from my mistakes. Thanks

Replies are listed 'Best First'.
Re: Perl CGI w/ Javascript
by idsfa (Vicar) on Oct 13, 2003 at 22:49 UTC

    Compare the output of your perl script with your working model, and you'll find you are missing an "if" in your javascript:

    var o = from.options[i]; if here -> (o.selected) {

    I cannot suggest strongly enough that you move towards a templating system (HTML::Template leaps to mind). This will help you to separate the HTML/Javascript logic from the Perl.

    Updated:
    You are also missing the closing parentheses in your onClick javascript.

    ...onClick="moveOptions(this.form.available,this.form.selected;" ...onClick="moveOptions(this.form.selected,this.form.available;"

    Remember, when you stare long into the abyss, you could have been home eating ice cream.
      Ok I added the if and thank you for pointing that out however I come out with the same results. Any other ideas? I will check out HTML::Template.
        Here's the rub - If you move to HTML::Template, the Javascript is now in a text file. More importantly, it's in a text file you can test without the use of Perl. So, you can get your Javascript right, THEN add in the Perl code.

        What I mean is that you build your HTML file and get it right with mocked up data. Then, you replace the mocked up piece with data from your script. But, by that point, you will know the Javascript is correct, so you don't have worry about it.

        ------
        We are the carpenters and bricklayers of the Information Age.

        The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

        ... strings and arrays will suffice. As they are easily available as native data types in any sane language, ... - blokhead, speaking on evolutionary algorithms

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

        As a general point, I would remove the JavaScript to a seperate js file which is refered to in the head section of your HTML file using a <SCRIPT SRC="myscript.js" /> tag. This adds a little more useful code / presentation seperation which improves your ability to test and may lead you to produce reusable code.

        inman

Re: Perl CGI w/ Javascript
by jeffa (Bishop) on Oct 14, 2003 at 01:35 UTC

    Perl has many ways of letting you print more than one line at a time. Trying to print lines of code, be it JavaScript or HTML or whatever, one line at a time is not only tedious, it is extremely error prone. That is, you are bound to make mistakes.

    Instead of trying to print lines of code, one line at a time, you could print one statement that spans more than one line:

    print "<html> <body> Hello World </body> </html> ";
    Notice that i never used "\n". Now notice what happens when i want to print something that contains double quotes:
    print "<h1 align=\"right\">Hello World</h1>";
    I have to escape the double quotes that are meant for the HTML renderer so the Perl interpreter does not close the quotation prematurely - but you already know this. You might have thought about using single quotes instead:
    print '<h1 align="right">Hello World</h1>';
    But you might have attempted to print out a newline "\n" and went back to double quotes and escaping. However, since Perl doesn't "freak out" on whitespace, you can do something like:
    print '<html> <body> <h1 align="right">Hello World</h1> </body> </html> ';
    But there are better ways. First off, single quotes are not a substitute for double quotes. They have different meaning. If you want to use the contents of a variable, you can use single quotes and concatenation:
    my $string = 'Hello World'; print '<h1 align="right">' . $string . '</h1>' . "\n";
    But it is so much more convenient to use double quotes and interpolation:
    my $string = 'Hello World'; print "<h1 align=\"right\">$string</h1>\n";
    If it weren't those darned escapes! Enter q (a substitute for the single quote) and qq (a substitute for the double quote - see Quote and Quote-like Operators for more).
    print qq(<h1 align="right">$string</h1>\n);
    If you look carefully you will notice that the parentheses are the delimiters for the string ... not double quotes. q and qq are magical in that they allow you to specify what the string delimiter(s) will be:
    print qq(<h1 align="right">$string</h1>\n); print qq{<h1 align="right">$string</h1>\n}; print qq#<h1 align="right">$string</h1>\n#; print qq!<h1 align="right">$string</h1>\n!; # have to escape the delimiter: print qq/<h1 align="right">$string<\/h1>\n/;
    Just about all of the "special" characters will do. But the topic is avoiding printing lines of code one line at a time, and doing so in a fashion that makes the code not only bug-free, but easy to maintain. Next stop, HERE docs.

    HERE docs are a valid solution, but they really aren't my favorite. The concept is actually the same as the one for the q and qq operators - you specify the delimiters. However, instead of using some special character that is eventually going to show up in your data (and you are going to have to go right back to escaping again), you can choose a string ... a VERY_LONG_STRING_IF_NEED_BE.

    my $string = 'Hello World'; print <<HTML; <html> <body> <h1 align="right">$string</h1> </body> </html> HTML
    This is probably a good solution for your level of programming right now. The solution i would like to recommend is HTML::Template, but i need to be sure that you have a good grasp of file permissions and opening files as a non-priveledged user.

    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)
    
Re: Perl CGI w/ Javascript
by BUU (Prior) on Oct 13, 2003 at 23:37 UTC
    I'm not sure of the exact error, but this is the output of diff: (out1.html is perl yourscript.pl > out1.html; out2.html is just copied/pasted from your example above)
    buu@its01:~$ diff out1.html out2.html 4c4 < <SCRIPT LANGUAGE="Javascript" type="text/javascript"> --- > <SCRIPT language="Javascript" type="text/javascript"> 8c8 < (o.selected) { --- > if (o.selected) { 11a12 > 34,36c35,37 < <td align="center"> < <input class="accessButton" type="button" value="Add +>>" onClick="moveOptions(this.form.available, this.form.selected;"><b +r> < <input class="accessButton" type="button" value="<<R +emove" onClick="moveOptions(this.form.selected, this.form.available;" +> --- > <td> > <input class="accessButton" type="button" value=">>" + onClick="moveOptions(this.form.available, this.form.selected);"><br> > <input class="accessButton" type="button" value="<<" + onClick="moveOptions(this.form.selected, this.form.available);"> 45a47 >