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

I'm writing a somewhat simple "Journal" page where I post some entries and people can comment on those entries. This means there are several entries on one page, and below each entry, is a form to post "Comments". After submitting a comment, and clicking a 'submit' button, two things should happen:

1. The PERL script /cgi-bin/hello_world.pl should execute.
2. The person should remain on the page (i.e. no page reload) and the content they put in the form should become an actual comment. (Appear as text above the input fields)

In the past, when submitting forms, I've simply used the format

<form class='frm' name='frm_name_1' id='frm_name_1' action='/cgi-bin/h +ello_world.pl' method='POST'>

and then in my PERL code, I've accessed the parameters simply by using the code

use CGI; use locale; $query = new CGI; $CommentText = $query->param('txt_content');

However, because I want the user to remain on the page and not have the page submit, instead of using a simple form POST method, I learned (through a lot of online searching) that I should be using jQuery instead -- which I have never used before. So, instead of my usual form code, I am using this instead:

<form class='frm' name='frm_name_1' id='frm_name_1' action='' method=' +POST'>

leaving the action parameter blank. And I have then added this script to the HTML page

<script type="text/javascript" src="http://code.jquery.com/jquery- +1.4.2.min.js"></script> <script type="text/javascript" src="http://ajax.microsoft.com/ajax +/jquery.validate/1.7/jquery.validate.min.js"></script> <script type="text/javascript"> $(document).ready(function(){ $('.frm').submit(function() { $.post('/cgi-bin/hello_world.pl'); return false; }); }); </script>

(Note, I don't really need to do any validations on the fields, I just need them submitted as is)

The problem is, that when I switch from doing the normal form POST, to this jQuery post -- the method that I am used to using in PERL to access the variables isn't working anymore.

use CGI; use locale; $query = new CGI; $CommentText = $query->param('txt_content');

The variable txt_content remains blank. I'm completely stuck!!

I'd be happy to share the entire code if needed, but hoping it's a straight forward solution. I've looked online and through this forum, but nothing seems to change the outcome. Any help would be greatly appreciated.



Secondary to this, in the jQuery script, after the form submits, I need to call a javascript function (that is already written and working fine) called "rewriteDiv(x)" where x is the name of the form that was just submitted - in this case "frm_name_1"). I know it's not a PERL related question at all -- but If anyone knows their jQuery and could also help me out with this, I'd appreciate it.

Replies are listed 'Best First'.
Re: Post from jQuery to Perl - can't access parameters
by marto (Cardinal) on Mar 13, 2013 at 14:05 UTC

    I suspect nothing is happening because your Perl script isn't getting called when you attempt this with jQuery. Your jQuery to deal with the submit actually isn't doing what you think it is. You need to explicity stop it from continuing as a normal form submission using preventDefault(). A full example can be found in the documentation for the post method http://api.jquery.com/jQuery.post/.

    If you're using Firebug you can aid basic debugging by writing things out to the console via console.log('Something went wrong here/meaningful error message');, and making logging/errors persistant. I suspect you're just reloading the form. Further you may be interested in Using Perl, jQuery, and JSON for Web development from the tutorials section.

    Update: this advice is spot on regards the printing of headers.

      The perl code is definitely getting called. I've ensured that it at least creates a debugging file and spits out the values (but the values are blank).

      The debugging file is being created and the output looks like:

      The comment text is:

      ...so I know that's not the problem -- but thanks for the reply.

        Your $.post() is not submitting any data, because you're not telling it what data you want to post. (jQuery is a nice library, but it isn't psychic - you need to tell it what data to post.) Try something like:

        $.post( '/cgi-bin/hello_world.pl', $('#frm_name_1').serialize() );
        package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: Post from jQuery to Perl - can't access parameters
by blue_cowdawg (Monsignor) on Mar 13, 2013 at 14:13 UTC
        The variable txt_content remains blank. I'm completely stuck!!

    I am not even going to attempt to troubleshoot your JQuery code. I can spell JQuery but that's about the extent of my knowledge on that subject.

    However: let me throw you a few bones and at least provide you a methodology that I'd probably use if this were one of my consulting assignments. Are you using Firefox? If you are there is a wonderful tool for Firefox that can aid in the debugging of JavaScript based code and especially things like what you are attempting to do. The name of the tool is (offsite link) Firebug. This tool well let you watch the interaction between the JavaScript code and your web server. There is also a tool specifically for JQuery that is a Firefox pluging called (offsite)FireQuery. I have no experience with it but maybe you can try that.

    Even more basic than that I'd suggest checking your sever logs and ensure that the POST is even happening.

    My next step would be to put some debugging code into the backend script on the server. A sniglet you can put in:

    sub barf_my_guts_out { my $cgi=shift; open TRACE,sprintf("> /tmp/%s.debug.%d.txt",$0,$$) or die "Cannot open trace log: $!"; printf TRACE "CGI Variables Passed: \n"; printf TRACE "%20s\t%30s\n\n","Key","Value"; foreach my $key($cgi->param){ printf TRACE "%20s\t%30s\n",$key,$cgi->param($key); } printf TRACE "\n\nEnvironment Values:\n"; printf TRACE "%20s\t%30s\n\n","Key","Value"; foreach my $key (sort keys %ENV){ printf TRACE "%20s\t%30s\n",$key,$ENV{$key}; } }
    You'd invoke that sub (lots of handwaving here) thusly:
    #!/usr/bin/perl -w use strict; use CGI; # more stuff my $cgi = CGI->new(); # or however my $verbose_debug=1; barf_my_guts_out() if $verbose_debug;
    This way you can turn the spew off in production by flipping the value of $verbose_debug to zero.

    Basic troubleshooting is based on an understanding of what the inputs are into a system and what the expected output should be. A system can always be broken down into smaller pieces that you can test the input to and output from in a methodical manner.


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
Re: Post from jQuery to Perl - can't access parameters
by golux (Chaplain) on Mar 13, 2013 at 14:24 UTC
    Hi stuckdev,

    Here's a fairly simple example that should do the basics of what you want:

    #!/usr/bin/perl -w ############### ## Libraries ## ############### use strict; use warnings; use CGI; use CGI::Carp qw{ fatalsToBrowser }; use JSON; ################## ## User-defined ## ################## my $jquery = "//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min. +js"; ################## ## Main program ## ################## my $query = new CGI; my $url = $query->url; my $txt_content = $query->param("txt_content") || ""; if ($txt_content) { handle_server_side_ajax($txt_content); exit; } print_html(); ################# ## Subroutines ## ################# sub handle_server_side_ajax { my ($text) = @_; print "Content-type: application/json\n\n"; # Do something with $text ... my $result = "You said '$text'"; my $time = localtime(time()); my $h_json = { 'result' => $result, 'time' => $time }; my $output = to_json($h_json); print $output; } sub print_html { print "Content-type: text/html\n\n"; print qq{ <script src="$jquery" type="text/javascript"></script> <script type="text/javascript"> var J = jQuery.noConflict(); function ajax_text() { var input = J('#text_input').val(); J.ajax({ url: "$url", cache: false, dataType: 'json', data: { txt_content: input }, success: function(json) { handle_ajax_output(json); } }); } function handle_ajax_output(json) { var result = json.result; var time = json.time; var text = "<br>Time: " + time + " &nbsp; Result: " + +result; J('#html_result').append(text); } </script> <body style="background:cyan"> <h2>JQuery Example</h2> <br>Enter Text and click Submit <br> <input id="text_input"> <input type="button" value="Submit" onclick="ajax_text() +"> <br><br> <h5>Ajax Results Below</h5> <pre id="html_result" style="background:#ffef9f"> </pre> </body> }; }

    Note that I used "var J = jQuery.noConflict();" so that I could type:

    var input = J('#text_input').val();

    without having to escape the usual '$' variable of jQuery. Otherwise I'd have had to do:

    var input = \$('#text_input').val();

    My guess is that you were getting a blank page because you didn't print the headers properly. For the server-side ajax, you need to at least print something like:

    print "Content-type: text/html\n\n";

    Or, what I usually use:

    print "Content-type: application/json\n\n";

    If you have access to your httpd logs (for example, in Linux they might be in "/var/log/httpd"), take a look at "access_log" (to see if the server-side code was called), and "error_log" (to see whether there were problems).

    By the way, you don't have to use jQuery to do what you're trying to do, but it does make it a lot easier (especially things like Ajax, which are greatly simplified by jQuery).

    Let me know if you have any questions about my code, and I'll be happy to elaborate further.

    say  substr+lc crypt(qw $i3 SI$),4,5

      Thanks. I've tried putting in your code. I have two issues (thus far). I'm getting the error:

      Can't locate JSON.pm in @INC (@INC contains: /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi /usr/lib/perl5/site_perl/5.8.8 /usr/lib/perl5/site_perl /usr/lib64/perl5/vendor_perl/5.8.8/x86_64-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.8 /usr/lib/perl5/vendor_perl /usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi /usr/lib/perl5/5.8.8 .) at hello_world.pl line 8. BEGIN failed--compilation aborted at hello_world.pl line 8.

      on the server. (I'm hosting from 2mhost, so I have no idea what this all means) Do they even have JSON?

      The other issue, is that my jquery post is directly in my HTML page, not within a function on a PERL page -- so I'm having a hard time extrapolating your code and putting it into straight HTML format because I'm not exactly what you're doing with the whole J. stuff.

        Hi stuckdev,

        As marto said, you need to have JSON installed. You could ask 2mhost to install it for you, or try to install it locally (if you have that capability). It's not a complete requirement, but JSON ("Javascript Object Notation") is a wonderful means of simplifying how data is serialized for passing between client and server.

        As for your HTML page, if it's separate from your CGI, you can just put everything printed out by subroutine "print_html() into the html page, except for the "Content-type:  text/html" (which will be printed for you automatically by the server, since it's in HTML.

        You would then change $url in the function ajax_text(), in this line:

        url: "$url",

        to be whatever the name of your actual CGI/Perl script was instead.

        However, please note that you will still need the headers printed from your server-side Perl/CGI script; eg.:

        print "Content-type: application/json\n\n";
        If you forget that, you'll get something like this error (from my /var/log/httpd/error_log file):
        [Wed Mar 13 11:41:37 2013] [error] [client 192.168.17.33] Premature en +d of script headers: 1023196.cgi, referer: http://mymachine.com/10231 +96.cgi

        Does that help you get further?

        say  substr+lc crypt(qw $i3 SI$),4,5

        This means your host don't have JSON instaled, depending on your hosting deal you may be able to install modules easily, or it could be something they have to do for you. This is not a Core module. Also 5.8.8 is a fairly old verison of Perl. See also here and here.

Re: Post from jQuery to Perl - can't access parameters
by 3blindmice (Initiate) on Mar 13, 2013 at 15:20 UTC

    You have to send the data with the .post.

    $.post("/cgi-bin/hello_world.pl",$("#frm_name_1").serialize());

    where #frm_name_1 is the id of your form. Serialize encodes the set of form elements as a string for submission.

    This would be even cleaner

    $.post("/cgi-bin/hello_world.pl",$(this).serialize());

      yes yes!! Tobyink had the same response -- and you made it even better by allowing the form name to be a variable (using "this" instead of the actual form name). Now, the last thing is to figure out how to call that rewriteDiv function after the form post!!

        The return false; should do the trick.

        Try removing the ";" after the serialize() function.