Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

repeating fields in CGI forms

by swiftone (Curate)
on Feb 05, 2003 at 19:33 UTC ( #232899=perlquestion: print w/replies, xml ) Need Help??
swiftone has asked for the wisdom of the Perl Monks concerning the following question:

This seems such a basic problem, I can't imagine there isn't an elegant solution...OTOH, since I haven't encountered it before now, I could be wrong.

I have a CGI form with the same fields for N sets of data, where N isn't hardcoded. For example, imagine a page where you wanted to enter/update multiple sets of data since the data is simple, such as book titles and authors.

We're entering a good amount of data, so we don't want to limit it to one book/author per page/form, but having N sets of info makes it surprisingly painful to feed through Data::FormValidator and HTML::FillInForm.

I have a solution, I'm just not satisfied with it.

I would just have repeated fields within the form, for example:
<input name="title"> <input name="author"> <hr> <input name="title"> <input name="author"> ..etc
but I can't just pass it through Data::FormValidator, because I'm really interested in the data at a sub-form level -- blank fields are acceptable if the entire subform is blank. Likewise, if I pass it through HTML::FillInForm, it will work correctly for filled in values, but will repeat previous values on any "blank" fields.

Here is my disliked solution:

In the code that generates the form, (For me, this is Template, but this holds true for any way of generating the form) I append a counter string to the field names, resulting in something like:

<input name="title01"> <input name="author01"> <hr> <input name="title02"> <input name="author02"> ...etc
Then I have my code cycle through 1..N (or until $q->param() says a given field wasn't passed) and create chunks of "subform" data, that I pass through Data::FormValidator (with a suitably dynamically altered input profile). If I don't like the results, I can just pass it back to HTML::FillInForm and it gives me the desired output.

This solution technically works, but it's cumbersome, makes my HTML templates messy and not designer-friendly, and in general doesn't reflect the elegance I've come to expect from Perl.

So my question is: Which of the different WTDI is cleaner? Thanks in advance.

Replies are listed 'Best First'.
Re: repeating fields in CGI forms
by Coruscate (Sexton) on Feb 05, 2003 at 22:21 UTC

    While it is possible to use the same field name multiple times ( for example will properly read the data in correctly), I think it would be odd to handle the data. With the same field names, you'd end up with two arrays in your example (one for names, one for authors) or if you wanted to get fancy, you could create an AoH or an AoA.

    Myself, I simply prefer using the number idea. It's simple to implement and simple to read the data in. Now, I don't use any of those modules you've mentioned, so I don't know if that increases difficulty for this or not, but here's some example code (untested):

    #!/usr/bin/perl -wT use strict; use CGI qw/:standard :cgi-lib *table/; my $max_fields = 10; # Number of times to repeat fields my $input = Vars; if ($input->{'q'} eq 'save data') { open my $fh, '>>', 'data.txt'; for (1 .. $max_fields) { next unless $input->{'title_' . $_} && $input->{'author_' . $_}; print $fh "$input->{'title_' . $_}|$input->{'author_' . $_}\n"; } close $fh; } print header(), start_html('My Data'), start_form(), start_table(), Tr( th( {align=>'left'}, 'Title' ), th( {align=>'left'}, 'Author' ) ); print Tr( td( textfield( {name=>"title_$_",size=>30,force=>1} ) ), td( textfield( {name=>"author_$_",size=>30,force=>1} ) ) ) for 1 .. $max_fields; print Tr( th( {colspan=>2}, submit( {name=>'q',value=>'save data'} ) ) ), end_table(), end_form(), end_html();

          C:\>shutdown -s
          >> Could not shut down computer:
          >> Microsoft is logged in remotely.

      Unfortunately, the modules mentioned are the exact reason for my distress. Data::FormValidator and HTML::FillInForm are both wonderful for validating and redisplaying form data. Unfortunately, they don't work well with "subform"ed data.

      And while your code to generate the form looks fine, any templating language is trying to create material that is easy for a non-programmer to edit...and "numbered" fields hurts that considerably.

Re: repeating fields in CGI forms
by markjugg (Curate) on Feb 06, 2003 at 16:31 UTC
    I've got a solution for this with Data::FormValidator. I'm just looking for someone to help code it. :) It should be pretty straightforward-- I'm in a time crunch myself.

    I would file a bug report against HTML::FillInForm for the issue you having it . If the module can get as far as it does-- correctly handling the populated fields, I think it ought to be able to handle the rest of them. Are you using the latest version, 1.01?


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://232899]
Approved by valdez
[choroba]: Yes, "tynovsky" there is my friend and ex-colleague, I needed to beat him at Fibonacci :-)

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (9)
As of 2017-10-20 09:08 GMT
Find Nodes?
    Voting Booth?
    My fridge is mostly full of:

    Results (260 votes). Check out past polls.