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

It won't get called unless you call it ;-)

I was kind of assuming that the Template code calls the subroutine at some point! After all, it gets passed the reference...

In the example code, get_user_projects doesn't seem to be explicitly called.

#!/usr/bin/perl use strict; use warnings; use Template; use CGI; $| = 1; print "Content-type: text/html\n\n"; my $file = 'userinfo.html'; my $vars = { 'version' => 3.14, 'days' => [ qw( mon tue wed thu fri sat sun ) ], 'worklist' => \&get_user_projects, 'cgi' => CGI->new(), 'me' => { 'id' => 'abw', 'name' => 'Andy Wardley', }, }; sub get_user_projects { my $user = shift; my @projects = ... # do something to retrieve data return \@projects; } my $template = Template->new({ INCLUDE_PATH => '/home/abw/websrc/src:/home/abw/websrc/lib', PRE_PROCESS => 'config', }); $template->process($file, $vars) || die $template->error();

Replies are listed 'Best First'.
Re^3: Preparing data for Template
by pryrt (Abbot) on Dec 31, 2020 at 00:51 UTC
    In the example code, get_user_projects doesn't seem to be explicitly called.

    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.

    I would assume that in your code, if you don't change to 'frames' => list_frames() (as already suggested), then you would need to call the frames as a function rather than treating it as a variable: probably like [% FOREACH frame IN frames() %] (untested)

    (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?)

      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.

        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 %]

        🦛

        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