Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

RFC: CGI::FormBuilder::Template::HTML::LoopedVariables

by hesco (Deacon)
on May 17, 2009 at 23:23 UTC ( [id://764566]=perlquestion: print w/replies, xml ) Need Help??

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

OK, This is a request for comments on the following proposed new module:

CGI::FormBuilder::Template::HTML::LoopedVariables

=head2 _prepare_looped_variables This method exists to prepare fields which will ultimately be rendered + inside of loops by the template, to be prepared for inclusion. This + permits one to iterate over a database query and generate one or mor +e form fields for each record, which are rendered with HTML::Template +. This method is intended to add one new template construct: <tmpl-var field-looped-[field_name]> making possible the following code: my $form = CGI::FormBuilder->new( template => '/path/to/template/below.tmpl', header => $header, submit => [ 'Process Group Action' ] ); $form->field( name => 'group_action', label => 'Action', type => 'select', options => { 'add_to_group' => 'Add to Group', 'remove_from_group' => 'Remove from Group', 'edit_group' => 'Edit Group', 'delete_from_list' => 'Delete from List' } ); my @loop_data; while (my $phone = $sth->fetchrow_hashref()){ my %row_data; my $name = 'group_action_' . $phone->{'phone_number_id'}; $row_data{'CHECKBOX'} = \$form->field( name => $name, label => '', type => 'checkbox', options => [ 'perform_group_action' ], sticky => 0, value => 'perform_group_action', ); $row_data{'FNAME'} = $phone->{'fname'}; $row_data{'LNAME'} = $phone->{'lname'}; $row_data{'EMAIL'} = $phone->{'email'}; $row_data{'PHONE'} = $phone->{'phone'}; $row_data{'LINKS'} = $self->_get_links_for_phone_list($phone->{'ph +one_number_id'}); push (@loop_data, \%row_data); } $form->tmpl_param(PHONES => \@loop_data); my ($html); if ($form->submitted && $form->validate) { my $field = $self->{'q'}->Vars; if($form->submitted eq 'Process Group Action'){ if($field->{'group_action'} eq 'add_to_group'){ $self->_add_phone_numbers_to_group($field); $self->{'q'}->delete('_submitted_Group_Actions'); } elsif($field->{'group_action'} eq 'remove_from_group'){ $self->_remove_phone_numbers_from_group($field); $self->{'q'}->delete('_submitted_Group_Actions'); } elsif($field->{'group_action'} eq 'edit_group'){ $self->_edit_group($field); $self->{'q'}->delete('_submitted_Group_Actions'); } elsif($field->{'group_action'} eq 'delete_from_list'){ $self->_delete_phone_numbers_from_list($field); $self->{'q'}->delete('_submitted_Group_Actions'); } } $html = $form->render(); } else { $html = $form->render(); } Using a template like the one below: /path/to/template/below.tmpl <DIV align="right" id="GroupAction" class="GroupAction" title="Group_Action"> <h3>Group Actions:</h3> <table> <tmpl_var form-start> <tr><td colspan="2"></td><td colspan="2">Call Group: <tmpl_var field-group> Group Action: <tmpl_var field-group_action></td><td colspan="2"><tmpl_var form -submit></td></tr> <tr><th>Tag</th><th>First Name</th><th>Last Name</th><th>Email</th><th>Phone</th><th>Actions</th></tr> <tmpl_loop name="PHONES"> <tr><td> <tmpl-var field-looped-CHECKBOX> </td><td> <tmpl-var name=FNAME> </td><td> <tmpl-var name=LNAME> </td><td> <tmpl-var name=EMAIL> </td><td> <tmpl-var name=PHONE> </td><td> <tmpl-var name=LINKS> </td></tr> </tmpl_loop> <tmpl_var form-end> INSERT_NEW_RECORD_HERE </table> </DIV> =cut
This new module seems necessary to address the issues raised at: CGI::FormBuilder, HTML::Template and @loop_data question and CGI::FormBuilder, HTML::Template and \@loop_data question; trying again. Of course if anyone has any ideas for addressing this need more easily, I am all ears.

-- Hugh

if( $lal && $lol ) { $life++; }

Replies are listed 'Best First'.
Re: RFC: CGI::FormBuilder::Template::HTML::LoopedVariables
by ELISHEVA (Prior) on May 18, 2009 at 04:54 UTC

    If I understood your original question correctly (and I am not sure I did), you would like to generate an HTML table where each row contains some contact information and a checkbox. At the top of the form is a set of group actions. When the form is processed you want to apply the group actions to each table row where the checkbox is checked.

    I'm not terribly familiar with the modules central to this issue, but since you seem to have gone quite a while without a solution, I'm going to give it a shot based on reading the module documentation.

    As near as I can tell from the documentation, CGI::FormBuilder only knows how to build one form in a template, not an array of forms. It seems that your first way of working around this was to treat all of the table rows as one big form and use <tmpl_loop> to generate each row. But this created another problem: how do you tell one row from another? CGI::FormBuilder only returns a hash keyed by field name. If all rows in the table have the same field names, how do you know which row is assigning the value to the field?

    In your various posts you've tried at least two solutions:

    • give each row of the table a checkbox with a different field name. That didn't work so...
    • invent a new template tag that will "make it work"

    I don't think either will work because the core problem isn't in CGI::FormBuilder nor in HTML::Template, but rather in how the two work together. CGI::FormBuilder is expecting you to generate a single form, not an array of forms. It appears to be matching the name of the field definition in your field array with the name of the field in the template definition. If your field array contains definitions for fields "checkbox_1" and "checkbox_2", but your template only contains a field "checkbox", CGI::FormBuilder doesn't know how to connect the field definitions to the template definition.

    If you look at all of the examples for CGI::FormBuilder they all involve non-repeating forms. If you really want to use CGI::FormBuilder and HTML::Template together to build a table, I suspect that you will need to manually generate a template where each table row contains a different set of form fields, doing something like this (pseudo code):

    #start table template my $sTemplate='<table><tmpl_var form-start>...<tr>...</tr>'; #generate table rows foreach my $iRow (0... $#loopData) { #generate field definitions qualified by row id # e.g. FNAME_$iRow # LNAME $iRow # CHECKBOX $iRow # append field definitions to row fields push @aFields, @aRowFields; # generate a template string using the above fieldnames $sTemplate .= "<tr>...<tmpl-var field-checkbox_$iRowId>...</tr>"; } #finish table $sTemplate='<tmpl_var form-end>INSERT_NEW_RECORD_HERE</table>'; #write template string out to a temp file #generate form using the temp file my $oForm = CGI::FormBuilder->new( fields => \@aFields, ... template => 'tmpForm.tmpl' ); $oForm->render();

    Best, beth

Re: RFC: CGI::FormBuilder::Template::HTML::LoopedVariables
by wfsp (Abbot) on May 18, 2009 at 13:36 UTC
    Reducing the detail and blowing in some white space, your template looks something like
    <table> <tmpl_var form-start> <tr> <td><tmpl_var form -submit></td> </tr> <tmpl_loop name="PHONES"> <tr> <td><tmpl-var field-looped-CHECKBOX></td> <td><tmpl-var name=FNAME></td> </tr> </tmpl_loop> <tmpl_var form-end> INSERT_NEW_RECORD_HERE </table>
    It might be a bit easier if you gave an example of how you would expect the above to render.

    I agree with ELISHEVA that adding an id to each field may be the way to go.

    I'm a great fan of H::T partly because it is lightweight and it would be a shame if it got mucked about with. :-)

    btw, <tmpl-var...> throws an error in H::T.

Re: RFC: CGI::FormBuilder::Template::HTML::LoopedVariables
by Anonymous Monk on May 18, 2009 at 03:15 UTC
    Can you explain what is it supposed to do? This example
    my ($html); if ($form->submitted && $form->validate) { my $field = $self->{'q'}->Vars; if($form->submitted eq 'Process Group Action'){ if($field->{'group_action'} eq 'add_to_group'){ $self->_add_phone_numbers_to_group($field); $self->{'q'}->delete('_submitted_Group_Actions'); } elsif($field->{'group_action'} eq 'remove_from_group'){ $self->_remove_phone_numbers_from_group($field); $self->{'q'}->delete('_submitted_Group_Actions'); } elsif($field->{'group_action'} eq 'edit_group'){ $self->_edit_group($field); $self->{'q'}->delete('_submitted_Group_Actions'); } elsif($field->{'group_action'} eq 'delete_from_list'){ $self->_delete_phone_numbers_from_list($field); $self->{'q'}->delete('_submitted_Group_Actions'); } } $html = $form->render(); } else { $html = $form->render(); }
    is too much typing. if($foo){print 1} else {print 1} so
    my ($html); if ($form->submitted && $form->validate) { my $field = $self->{'q'}->Vars; if($form->submitted eq 'Process Group Action'){ if ... } $html = $form->render();
Re: RFC: CGI::FormBuilder::Template::HTML::LoopedVariables, that is a Never Mind
by hesco (Deacon) on May 29, 2009 at 22:06 UTC
    My appreciation to Beth, who gave me a clue for moving this forward. Here is the code I finally used to achieve me end:

    my @loop_data; my $phone_lines; while (my $phone = $sth->fetchrow_hashref()){ my $name = 'group_action_' . $phone->{'phone_number_id'}; my $this_phone_line = $phone_line; my $links = $self->_get_links_for_phone_list($phone->{'phone_numbe +r_id'}); $this_phone_line =~ s/CHECKBOX/<tmpl_var field-$name>/; $this_phone_line =~ s/FNAME/$phone->{'fname'}/; $this_phone_line =~ s/LNAME/$phone->{'lname'}/; $this_phone_line =~ s/EMAIL/$phone->{'email'}/; $this_phone_line =~ s/PHONE/$phone->{'phone'}/; $this_phone_line =~ s/LINKS/$links/; $phone_lines .= $this_phone_line . "\n"; $form->field( name => $name, label => '', type => 'checkbox', options => [ ' ' ], sticky => 0, ); } open('TEMPLATE_COMPILED','>',$template_compiled); open('TEMPLATE','<',$template); while(<TEMPLATE>){ if(m/PHONE_LINE/){ $_ =~ s/PHONE_LINE/$phone_lines/; } print TEMPLATE_COMPILED $_; } close('TEMPLATE'); close('TEMPLATE_COMPILED');
    I essentially built the template as I went; and as I created each of the form elements. Accumulated the elements into a scalar and then used a string substitution to stitch together a complete custom template that accomodated the data.

    I don't think I will be creating that new module to extend HTML::Template at this time. But thanks anyway. And thank you Beth for pointing the way.

    if( $lal && $lol ) { $life++; }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://764566]
Approved by planetscape
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (6)
As of 2024-04-26 09:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found