chaoticset has asked for the wisdom of the Perl Monks concerning the following question:
I'm hideously new to the CGI module, and I've been trying to *read* through the docs. Not fun.
However, in between reading the docs, I try to slap a little code together, figuring that getting it on my hands will teach me better than getting it on my eyes (at first).
Now, I know how to do something to each instance of an array.
foreach $thing (@thingies) { something($thing) }
And I've seen how to generate a table from the CGI documentation. (And I won't duplicate it here since I'm working with the copied code before I try to write my own.)
The question: You can't interpolate whole subs, right? So if I do a print statement with a foreach inside it, that's not going to work. Should I slap it all into a hash, or is can I print pieces separately and put the table-stuff *around* the foreach, printing each little chunk of the array as three different table elements by passing them into a short, three-element array?
Is all of this going to make for a prohibitively long return time, considering that the array is going to have 1000+ elements?
Should I give up, and go back to my old job at Subway?
(The last is rhetorical. I know I should go back. I just don't want to.)
Apologies in advance for the time this wastes, and here's hoping I have better questions soon enough.
Re: Yet Another Stupid CGI Question
by Zaxo (Archbishop) on Oct 19, 2001 at 05:41 UTC
|
print map {something($_)} @thingies;
There are many other ways. Keep on trying things, perl gives you lots of choices besides Subway ;-)
After Compline, Zaxo | [reply] [d/l] |
Re: Yet Another Stupid CGI Question
by mandog (Curate) on Oct 19, 2001 at 06:32 UTC
|
| [reply] |
Meta-reply
by Fletch (Bishop) on Oct 19, 2001 at 08:02 UTC
|
Not a direct answer to your question, but you probably
don't want to return a page with a table with 1000+ rows
in it. For one thing, you may kill some browsers. If it
doesn't kill the browser, it'd probably take aeons to
render it.
A better solution might be to return just a subset of
the records (10, 25, or 50 are popular choices) and provide
a means to page through the results (pass along an extra
couple of paramters that are the chunk size and the current
location in the result set).
| [reply] |
|
| [reply] |
Re: Yet Another Stupid CGI Question
by chaoticset (Chaplain) on Oct 19, 2001 at 09:19 UTC
|
Sorry - I should have been more specific about what I'm doing. This should address the questions.
When the user first clicks on the page, it will dump a text box in front of them, saying 'Enter the first few letters.' Based on that, the program will load and weed out all the entries in the 1000+ array that have those first few letters. Then, it returns a page with the text box at the top(so they know what they typed in) and *just* the matching entries.
Based on the distribution of beginning letters, I'd say they'd never get a return page with more than 100 entries on it. (At most, maybe 200.) I realize those are stretching, but I honestly don't think they'd happen often. (If they did during testing, I could build a page-breaker and make it return two pages.)
Now, I realize all this is *way* too much to ask for. I'm not asking for it. All I'd like is a little advice on how to handle turning this data into a web page.
It's going to be:
name=cost=number
And it will come out in a table with a few other things: (chk = checkbox, txt = textfield)
--------------------------------
|chk|name|cost|number|txt|
--------------------------------
Now, as I understand Perl, it doesn't interpolate while or for loops. So if I make the statement
print table(...
...
foreach ... {
...
...
}
...
)
then my code won't work, because the for hasn't been dealt with before the print tries to print.
Am I wrong? Are these things dealt with automagically, and Perl is just all the more amazing? I'm thinking it's not. Does this mean I have to do the table tags by hand?
| [reply] |
|
A couple of things that might make your life a bit
easier:
- The map function can often be used as an
"inline foreach".
- In CGI.pm, the Tr and td functions
(amongst others) have a neat feature whereby if you pass
them a reference to an array, then they return a <tr> or
<td> tag for each element in the array.
I don't know what your data structure looks like, but
this sample code might help:
my @list = ('chk1|name1|cost1|number1|txt1',
'chk2|name2|cost2|number2|txt2',
'chk3|name3|cost3|number3|txt3');
print table(Tr([map { td([split /\|/, $_])."\n" } @list ]));
--
<http://www.dave.org.uk>
"The first rule of Perl club is you don't talk about
Perl club."
| [reply] [d/l] |
|
My £/50 is to second the monk who said HTML::Template. In fact I don't think it's terribly difficult to learn, certainly not to get it to do what you want. You'd make a template file, say you call it results.tmpl which wd look something like:
<table bgcolor=#66aaff border=2 bordercolor=#ffffff cellspacing=0 cell
+padding=6>
<TMPL_LOOP RESULTS>
<tr>
<td>
<TMPL_VAR CHK>
</td>
<td>
<TMPL_VAR NAME>
</td>
<td>
<TMPL_VAR COST>
</td>
<td>
<TMPL_VAR NUMBER>
</td>
<td>
<TMPL_VAR TXT>
</td>
</tr>
</TMPL_LOOP>
</table>
(I like writing my TMPLs in upper case and my HTML in lower case to tell them apart visually - no other reason).
Then in your perl you need a bit that looks like this
#!/usr/bin/perl -w
use strict;
use CGI qw(:standard);
use HTML::Template;
# my guess about what your data structure might be:
my %information = (
txt_foo => ['chk_foo','name_foo','cost_foo','number_foo'],
txt_bar => ['chk_bar','name_bar','cost_bar','number_bar'],
txt_baz => ['chk_baz','name_baz','cost_baz','number_baz'],
);
# initialise the template and other vars:
my $results_tmpl = HTML::Template->new(filename => 'results.tmpl');
my @results;
# populate @results with the data from %information:
for (keys %information) {
my %row_data;
$row_data{'txt'} = $_;
$row_data{'chk'} = $information{$_}[0];
$row_data{'name'} = $information{$_}[1];
$row_data{'cost'} = $information{$_}[2];
$row_data{'number'} = $information{$_}[3];
push @results, \%row_data;
}
# drop the info into the template:
$results_tmpl->param(results => \@results);
# print the page:
print
header,
start_html,
$results_tmpl->output(),
end_html;
Simple, really. The marginally tricky bit is getting the data into the right form to go into the template. The single line $results_tmpl->param(results => \@results); is doing duty for a lot of lines like
$results_tmpl->param(
results => (
txt => 'txt_foo',
chk => 'chk_foo',
......
But obviously if you had to write it all out by hand, you might as well not be using the template at all. What I'm saying is that the code for populating the template will work, but it may take a bit of effort to get your head around it (it did mine). But you said you wanted to get it on your hands...
The only other problem I can foresee is that for some reason HTML::Template doesn't seem to be part of the standard issue. If you're using an ISP that doesn't offer it, you may want to refer to these threads.
update :Reflectingthat this is a problem I quite often come up against, and for which I wd like a simple solution, I had a sudden rush of blood to the head and wrote a module that makes it easier to do printing out lists of info in CGI, so now there's yet One More Way To Do It. Now you can do this, which I think you'll agree has a certain classical simplicity:
#!/usr/bin/perl -w
use strict;
module library
use CGI qw(:standard);
use CGI::tab;
my %information = (
txt_foo => ['chk_foo','name_foo','cost_foo','number_foo'],
txt_bar => ['chk_bar','name_bar','cost_bar','number_bar'],
txt_baz => ['chk_baz','name_baz','cost_baz','number_baz'],
);
print
header,
start_html,
start_tabs(75,150,225,300);
for my $key (keys %information) {
print $key,t;
print $_,t for @{ $information{$key} };
}
print
end_tabs,
end_html;
§ George Sherston | [reply] [d/l] [select] |
|
There's a bunch of ways to do this.
Here's two.
# One Way
my $table_dat = undef;
foreach my $ell (@elements){
$table_dat.=Tr(td(b("Label")),td($ell)); # Whatever you need to ou
+tput.
}
print table($table_dat);
# Second way
use CGI qw/:standard *table/; # Import start_table and end_table
print start_table
# Data processing here to spit out rows and cells...
foreach my $ell (@elements){
print Tr(td(b("Label")),td($ell));
}
print end_table
-Lee
"To be civilized is to deny one's nature." | [reply] [d/l] |
Re: Yet Another Stupid CGI Question
by alien_life_form (Pilgrim) on Oct 19, 2001 at 12:57 UTC
|
Greetings.
Not understanding while you want to interpolate the entire sub, I would offer more ways to do it.
(1)
# Trivial double loop - build, then print
my $aref=[]; #reference to anonymous array.
foreach $thing (@thingies) {
push @{$aref},foo($thing);
}
print_table($aref);
#...
sub print_table {
my $aryref=shift
foreach my $thing (@{$aryref}) {
#etc.
}
}
(2)
#bypass cgi's html facilities
print '<table>';
foreach $thing (@thingies){
#foo returns an array of cell contents.
print '<tr><td>',join('</td><td>',
foo($thing)),'</td><tr>';
}
print '</table>';
CGI's html convenience functions are - IMHO - just that, convenience (as opposed to the powerful parameter parsing, handling, etc. where CGI unreplaceably shines).
Sometimes rolling your own html can be just the thing.
Cheers,
alf | [reply] [d/l] [select] |
Re: Yet Another Stupid CGI Question
by Armos (Scribe) on Oct 19, 2001 at 05:48 UTC
|
I too am learning CGI... it's a little crazy at times, but it certainly can do some really neat stuff. I'm not certain exactly what you are asking. When I worked with CGI, I had trouble outputing complex tables, so I usually ended up printing raw HTML. I ended up using CGI to handle the parameters, and then generated any HTML tags myself.
To clarify a little, you are trying to use the tr and td subs with the print function to generate a complex table? And you are wondering how to get it to work?
-A
| [reply] |
Re: Yet Another Stupid CGI Question
by buckaduck (Chaplain) on Oct 19, 2001 at 16:17 UTC
|
use CGI ':standard';
use HTML::Table;
my $table = new HTML::Table;
foreach my $thing (@thingies) {
my ($name,$cost,$number) = GetThingInfo($thing);
$table->addRow(
checkbox('checkboxname'),
$name,
$cost,
$number,
textfield('textname'),
);
}
$table->print;
buckaduck | [reply] [d/l] |
Re: Yet Another Stupid CGI Question
by netjackal (Acolyte) on Oct 19, 2001 at 14:26 UTC
|
Instead of putting the foreach loop in the print statement itself you could always do something like this
my @array = ( 4,5,3,4,5);
print function(),"\n";
sub function {
my $rv;
foreach my $item (@array) {
$rv .= $item . "\t";
}
return $rv;
}
and put the foreach loop in a sub (or anon. sub). I know the example above looks silly but i had to work the foreach in to illustrate my point.
HTH | [reply] [d/l] |
Re: Yet Another Stupid CGI Question
by robot_tourist (Hermit) on Oct 19, 2001 at 14:33 UTC
|
u could put your html tags in the function, then u wouldn't have to worry about interpolation. | [reply] |
Re: Yet Another Stupid CGI Question
by ronzomckelvey (Acolyte) on Oct 24, 2001 at 07:54 UTC
|
Hi-
I had your same question on tables and such months ago, but I just did it my own way.
I also use CGI for most of the stuff, but I hardcode the html for tables and other minor crap. I've built a few systems that display lots and lots of data, and I use tables for that.
Depending on what I'm doing I either handle everyline being displayed as a seperate table, this way the data get displayed as the browser gets it, not when the table is complete.
For smaller tables, I use one table, with TR for each line of data, but I still so it on my own.
ronzo | [reply] |
|
|