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

Background: Used raw DBI, CDBI, poked briefly at DBIC and now settled on Rose::DB::Object. All interfacing with web pages without any particular engine in the way/helping.

I've had a few web apps where I needed to present a list of options and show the selected option. Low volume sites, so all very easy to do with Template and something like:

<select name="whatever"> [% FOREACH option = whatever_options %] <option value="[% option.value %]" [% IF whatever == option.value %] selected="1" [% END %]> [% option.name %]</option> [% END %] </select>

Now I've hit a case where I have a <select multi="1"> dialog, so obviously the above Does Not Work.

In perl I have a list of objects representing the possible values (lets say categories), and another list representing the values selected for the current viewed object (lets say an article).

Some paths:

I *have* to generate a sane single list and pass to Template, anything else is wrong, but I'm unsure as to the best way to deal with this.

Replies are listed 'Best First'.
Re: populating <select multi="1"> from ORM
by merlyn (Sage) on Jul 05, 2007 at 19:47 UTC
    Sounds like your list needs to become a hash, with stuff like { barney => 0, fred => 0, dino => 1, betty => 1 } as in, "... and these items are selected". And then you can map the keys, and look up each value to see whether to add selected=1 or not.

    You can even have a legacy call that creates the hash for the new call, so that you have to maintain only one piece of TT code. The legacy call would would take a list and a 'selected', and generate a call to the new call with a hash that has only 0 or 1 'selected' set to 1.

      I'm assuming you suggesting all this lookup happens in perl rather than TT. That would be a list of hashrefs, as when presenting the <options> in the <select> I need to have the correct order, and each element would need to have at least
      • value
      • display name
      • selected
      Thats pretty much where I'd ended up, it just feels a little unclean to convert an array of objects to an array of hashrefs in order to pass to TT. Thats probably just me viewing everything as 'should be Object nail' since I bought into the OO-perl hammer :)
Re: populating <select multi="1"> from ORM
by siracusa (Friar) on Jul 06, 2007 at 01:37 UTC

    Have you considered using Rose::HTML::Objects? Here's a minimal, quick solution to your specific issue:

    $field = Rose::HTML::Form::Field::SelectBox->new( name => 'whatever', multiple => 1, options => [ 1 => 'One', 2 => 'Two', 3 => 'Three' ], size => 3); $field->input_value([ 1, 3 ]); print $field->html;

    or in TT-speak:

    [% field.html %]

    both of which produce:

    <select multiple name="whatever" size="3"> <option selected value="1">1</option> <option value="One">One</option> <option value="2">2</option> <option value="Two">Two</option> <option selected value="3">3</option> <option value="Three">Three</option> </select>

    You can manage your whole form using Rose::HTM::Objects as well, of course:

    $form = Rose::HTML::Form->new; $form->add_fields ( whatever => { type => 'select box', multiple => 1, options => [ 1 => 'One', 2 => 'Two', 3 => 'Three' ], size => 3, }, ... ); # Pass in form params from various sources: # Hashref $form->params({ whatever => [ 1, 3 ] }); # CGI object $form->params_from_cgi($cgi); # $cgi "isa" CGI # Apache request object (mod_perl 1 or 2) $form->params_from_apache($r); # Initialize the fields based on params $form->init_fields();
    Then, finally:
    print $form->start_html, $form->field('whatever')->html, ... $form->end_html;

    or in TT:

    [% form.start_html %] [% form.field('whatever').html %] ... [% form.end_html %]

    (For XHTML output, just replace the "html" method calls with "xhtml")

    Yeah, I'm sure it looks "heavyweight", but life's too short to be manually producing form widget markup using TT, or any other templating language, IMO :)