hermit23 has asked for the wisdom of the Perl Monks concerning the following question:
Dear Brothers
I have a .cgi script which outputs an HTML page.
The HTML page includes a short jquery script which draws a graph on the HTML page.
The critical line in the jquery script is:
<script> var data=[[0,170],[1,27],[2,3],[3,0],[4,0],[5,0],[6,0],[7,0],[8,0],[9,0],[10,0]];
where the bits in square brackets are positions and data.
This works fine as long as the data line is hard coded, but I normally don't know what the data is going to be till the .cgi script has run.
Ideally, I'd like to write a line like this:
<script> var data=$mydata where $mydata is a string prepared by the cgi script. However, jquery seems not to like this. I think this, is because it interprets the $ as a reference to itself.
Does anyone have any suggestions how to solve this?The general question is how do I move smoothly between perl and jquery?
Re: jquery scripts
by Corion (Patriarch) on Oct 02, 2015 at 09:25 UTC
|
In your templating system, have the positions interpolate as a string instead of using a literal variable $mydata. If you can show us a (tiny) example script that does what you describe, we can likely point out better what you need to change.
Basically, I imagine your script being:
#!perl -w
use strict;
my $mydata = "[[0,170],[1,27],[2,3],[3,0],[4,0],[5,0],[6,0],[7,0],[8,0
+],[9,0],[10,0]]";
print <<'HTML';
<html>
<head>
<script src="jquery.js"></script>
<script>
var data=$mydata;
</script>
</head>
<body>
<h1>Hello</h1>
</body>
HTML
In that case, the easiest approach would be to change the interpolation to double quotes.
The best approach is to use a proper templating system like HTML::Template or Template::Toolkit. | [reply] [d/l] [select] |
|
Or, if your data are stored in an array in Perl, use a JSON module to convert them to JSON:
my @mydata = map [ $i++, $_ ], 170, 27, 3, (0) x 8;
my $json = to_json(\@mydata);
print << "HTML";
<html>
<head>
<script src="jquery.js"></script>
<script>
var data=$json;
</script>
</head>
<body>
<h1>Hello</h1>
</body>
HTML
| [reply] [d/l] |
Re: jquery scripts
by golux (Chaplain) on Oct 02, 2015 at 17:24 UTC
|
Hi hermit23,
Here's a short but complete example of a self-contained CGI script that will query the server and display the data points it gets back.
It makes use of Javascript/jQuery, and calls back to the server once, using Ajax to get the data points, which it then displays to page. You can, of course, modify the subroutine "server_side_ajax()" to have more meaningful points than the random ones my script generates. Plus, you can do something more fun with the points in the javascript function "done_query" than just print them to the page.
Of course, let us know if you have any questions.
Update: And if you were only asking about how not to use '$', pay special attention to the line "var J = jQuery.noConflict();" which enables the magic letting you refer to jQuery with 'J' (or whatever else you like) instead of '$'.
#!/usr/bin/perl
###############
## Libraries ##
###############
use strict;
use warnings;
use JSON;
##################
## User-defined ##
##################
# This is a link to Google's publicly-available jQuery library
my $jquery = "ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js
+";
##################
## Main Program ##
##################
my $this_prog = $ENV{'REQUEST_URI'};
my $h_param = cgi_params();
if (exists $h_param->{'ajax'}) {
# If 'ajax' was sent in the URL, it's the client communicating
# with the Server via Ajax. See function ajax_query_server(),
# which initiates this. You could also put '?ajax' in the URL
# query to see the data results directly.
##
server_side_ajax();
} else {
# If the URL doesn't contain the key 'ajax', we display the HTML
# page normally.
##
print "Content-type: text/html\n\n";
print_javascript();
print_html_page();
}
#################
## Subroutines ##
#################
sub cgi_params {
my $query = $ENV{'QUERY_STRING'} || 0;
$query or return { };
my $h_params = { };
foreach my $key (split('&', $query)) {
my $val = ($key =~ s/=(.*)$//)? $1: undef;
$h_params->{$key} = $val;
}
return $h_params;
}
sub server_side_ajax {
# Calculate data somehow
my $a_data = [ ];
my $npoints = 16;
# For the sake of example, just randomize it for now
for (my $i = 0; $i < $npoints; $i++) {
my ($x, $y) = (int(rand(100)), int(rand(100)));
push @$a_data, [ $x, $y ];
}
my $h_json = { 'data' => $a_data };
# Print the JSON header and data
print "Content-type: application/json\n\n";
print to_json($h_json);
exit;
}
sub print_javascript {
# Send the jQuery/Javascript code to the browser
print qq{
<head>
<script src="https://$jquery"></script>
<script>
// I prefer 'J' to '$' for jQuery within Perl
var J = jQuery.noConflict();
J(function() { ajax_query_server() });
// Here the browser talks to the server
function ajax_query_server() {
J.ajax({
url: "$this_prog",
dataType: 'json',
data: { ajax: 1 },
success: function(json) { done_query(json); }
});
}
// Here the browser gets data back from the server
function done_query(json) {
var a_points = json['data'];
for (var i = 0; i < a_points.length; i++) {
var x = a_points[i][0];
var y = a_points[i][1];
var text = "Point "+(i+1)+": ("+x+","+y+")\\n";
J('#data').append(text);
}
}
</script>
</head>
};
}
sub print_html_page {
# Here's where the HTML body gets printed
print qq{
<body style="background:peachpuff">
<h3> Ajax Data Example </h3>
<pre id="data"></pre>
</body>
};
}
say
substr+lc crypt(qw $i3 SI$),4,5
| [reply] [d/l] [select] |
Re: jquery scripts
by hermit23 (Initiate) on Oct 05, 2015 at 07:49 UTC
|
dear brothers
Thank you for your helpful answers to my question about jquery scripts
My solution to this problem is shown in the short cgi program below. However, I can't help feeling that this solution is not just clunky, but probably heretical. Can you show me the way to do it properly?
#!/usr/bin/perl -w
use CGI ':standard'; use CGI::Carp(fatalsToBrowser);
print "Content-type: text/html\n\n";
###data in Json format is prepared by the cgi script and added to the
+first line of the script
my $dline="<script> var data=[[1,13],[2,25],[3,17],[4,3],[5,10]];";
###$pt2 defines what the graph output looks like.
my $pt2='var dataset = [{data: data}];
var options = {series: {lines: { show: true },points: {radius
+: 3,show: true} } };
$(document).ready(function (){$.plot($("#mychart"), dataset,
+options);});
</script>
';
###$pscript is a jquery script made up of $dline and $pt2
my $pscript=$dline.$pt2;
##code for HTML output
my $htmlHeader='
<!DOCTYPE html PUBLIC>
<html>
<head>
<style>
body { background: #99bbee;}
#mychart {width:250px;height:300px;background:white;}
</style>
<script src="jquery-1.11.3.min.js"></script>
<script src="jquery.flot.min.js"></script>
</head>
';
my $body='
<body>
<div id="mychart"></div>
<p><hr><p>
</body>
</html>
';
###print the graph
print qq($htmlHeader);
print qq($body);
print qq($pscript);
| [reply] [d/l] |
|
The traditional approach is to move the HTML into a templating system instead of several print statements. This allows you to keep your code separate from the presentation part in the template. Depending on your workflow, this makes it possible for people other than you to change the HTML as it is generated.
For example using Template::Toolkit:
use strict;
use Template;
my $json = '[[1,13],[2,25],[3,17],[4,3],[5,10]]'; # or use JSON.pm
use CGI ':standard'; use CGI::Carp(fatalsToBrowser);
print "Content-type: text/html\n\n";
my $tmpl = Template->new();
$template->process('/home/hermit23/mysite/mytemplate.tt', {
json => $json,
});
With the template file /home/hermit23/mysite/mytemplate.tt containing:
<!DOCTYPE html PUBLIC>
<html>
<head>
<style>
body { background: #99bbee;}
#mychart {width:250px;height:300px;background:white;}
</style>
<script src="jquery-1.11.3.min.js"></script>
<script src="jquery.flot.min.js"></script>
<script>
var data= [% json %];
var dataset = [{data: data}];
var options = {series: {lines: { show: true },points: {radius
+: 3,show: true} } };
$(document).ready(function (){$.plot($("#mychart"), dataset,
+options);});
</script>
</head>
<body>
<div id="mychart"></div>
<p><hr><p>
</body>
</html>
Note the [% json %], which will get replaced verbatim by the value of the json key in the parameters to ->process(...) | [reply] [d/l] [select] |
|
If you're going to use CGI ':standard'; then use header() instead of "Content-type: text/html\n\n";
| [reply] [d/l] [select] |
|
| [reply] |
Re: jquery scripts
by sundialsvc4 (Abbot) on Oct 02, 2015 at 15:49 UTC
|
A templating system can be used to construct a Perl-friendly string containing the necessary data ... but also, this is essentially what the JSON format already is. (Originally, the idea behind JSON was that a JavaScript client could simply eval the string, but those innocent days are gone now.)
It is impossible for you to refer to a Perl variable, such as $mydata, in the web-page text that you send to the client, because the client has no idea where the web-page came from and has no access at all to the (Perl) software that may have produced it. Directly or indirectly, it must see a JavaScript statement that it can correctly parse and execute. The (Perl) server must use the content of its (Perl) variable to generate syntactically-correct and executable JavaScript literals.
| |
|
"It is impossible for you to refer to a Perl variable, such as $mydata, in the web-page text that you send to the client, because the client has no idea where the web-page came from and has no access at all to the (Perl) software that may have produced it."
Proving once again that you have no idea what you're talking about. This is possible and quite common. You replied after other users provided working example code (an alien concept to you I know) that shows how to achieve this.
| [reply] |
|
| [reply] |
|
| [reply] |
|
|