in reply to Re^3: Preparing data for Template
in thread Preparing data for Template

Not in the Perl. But in the template, the line [% FOREACH project IN worklist(me.id) %] calls worklist as a function with the appropriate ID as its argument.

That confirms what I suspected - thanks

(But it seems to me that you shouldn't need to call a function from the template, unless the data will change based on some parameter from the template, like the me.id argument in the tutorial example. Since you're not feeding anything back to the function, why not just define frames as the arrayref rather than the coderef?)

This is a learning exercise rather than a complete solution. Totally agreed that a function is not needed here yet, but I'm trying to learn how to use functions within Templates so that, when I need them, I have a good grasp of how to implement them.

Update:

probably like [% FOREACH frame IN frames() %] (untested)

Yes - that is the part I omitted...thanks, that gets me further.
The subroutine is now being called. However, the values are not being passed back to the Template. Or, if they are, they are not getting displayed.

Replies are listed 'Best First'.
Re^5: Preparing data for Template
by hippo (Archbishop) on Dec 31, 2020 at 11:47 UTC
    However, the values are not being passed back to the Template. Or, if they are, they are not getting displayed.

    Here is an SSCCE to demonstrate looping over the return values:

    #!/usr/bin/env perl use strict; use warnings; use Template; sub baz { return qw/there World/; } my $v = { bar => \&baz }; my $t = join '', <DATA>; Template->new->process (\$t, $v); __DATA__ [% FOREACH foo IN bar() %] Hello [% foo %]! [% END %]

    🦛

      Thanks hippo.
      Based on your code sample and what I already have, I have built a test which shows it is not the way I am using Template that is the issue - it is my display() function. In the 'real' code this is abstracted into a Site::HTML module because I want to hide the site variables away in a separate module with only Site::HTML and Site::Common having access to it - perhaps I need to rethink that design.

      use Template; use strict; my $template = Template->new; my $vars = { 'frames' => \&get_frames }; $template->process('test.tt', $vars); # this works display('test', $vars); # this doesn't sub get_frames { my @list; foreach my $l( qw/first second/ ) { my $fr = { 'one' => $l, 'two' => $l, }; push @list, $fr; } return @list; } sub display { # my $self = shift; my $file = shift; my %vars = @_; $template->process("$file.tt", \%vars); }

      update

      The test Template...

      Start test... [% FOREACH frame IN frames() %] Frame - [% frame.one %] [% frame.two %] [% END %] End test...

        You are passing a hash reference:

        display('test', $vars);
        ... but you are expecting a "hash" (well, list of pairs):

        sub display { # my $self = shift; my $file = shift; my %vars = @_;

        Most likely in display, you want instead:

        sub display { my( $file, $vars ) = @_; $template->process("$file.tt", $vars); }
Re^5: Preparing data for Template
by GrandFather (Saint) on Jan 01, 2021 at 09:14 UTC

    Does this journey tell you anything about the advisability of mixing presentation and code in this fashion? This sort of popping back and forth between presentation and code makes for maintenance headaches. It's also a great temptation with Template Toolkit. For something simple like populating a list with HTML::Template you can:

    use strict; use warnings; use HTML::Template; my @items = map {{item => $_}} qw(first second third fourth); my $template = HTML::Template->new(filehandle => *DATA); $template->param(items => \@items); print $template->output(); __DATA__ <TMPL_IF name="items"> <ul><TMPL_LOOP name="items"> <li><TMPL_VAR name="item"></li></TMPL_LOOP> </ul></TMPL_IF>

    Prints:

    <ul> <li>first</li> <li>second</li> <li>third</li> <li>fourth</li> </ul>

    and renders as:

    • first
    • second
    • third
    • fourth
    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
      Does this journey tell you anything about the advisability of mixing presentation and code in this fashion?

      Mixing presentation and code is exactly what I am trying to avoid.
      The 'real' code will have multiple values pulled from the backend DB, not just one value which is why I put them in an anonymous hash. Having said that, for this part of the code at least, the values will be static in the sense that they won't change during the runtime so having Template call a function won't be necessary.

      I think perhaps I need to do some more studying of the different kinds of loop that Template offers. Already I have changed quite a bit of what I have written so that one template file includes another instead of having the code process each separately...so much to learn!