http://qs321.pair.com?node_id=314591

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

Hi Monks,

I've a template (simplified to reduce clutter) that is used for two slightly different html outputs. Basically, in one output, a list of school names is included while in another, it's not. The relevant template and code are as follows:

Updated

# the template named generic.tt <tr><th align="center" colspan="2"><tmpl_var name=des></th> <tr><td><tmpl_var escape=html name=label></td><td><input type="text" n +ame="<tmpl_var escape=html name=field>" size="<tmpl_var escape=html n +ame=value>"></td></tr> <tmpl_if name=if_more> <select name="school_id"><option selected value="1"><option selected v +alue="0">Select<tmpl_loop name=options> <option value="<tmpl_var name=school_id>"><tmpl_var escape=html name=s +chool></option></tmpl_loop> </select></td></tr> </tmpl_if> <tr><td align="center" colspan="2"><input type="submit" name="action" +value="<tmpl_var escape=html name=submit>"></td></td> # template output 1 # prints school names as well # school names are stored in @options # this part works # @options already set prior to setting up the template params my %hash; %hash ( des => 'Form 1', # field label label => 'Label 1', # name of field field => 'field1', # size of text input field value => '5', submit => 'submit', if_more => 'true', # list of schools options => \@options, ); # call generate to output the template generate(\%hash); # template output 2 # don't print school names %hash ( des => 'Form 2', # field label label => 'Label 2', # name of field field => 'field2', # size of text input field value => '10', submit => 'submit', if_more => 0, ); generate(\%hash); sub generate { my $hashref = shift; my $template = HTML::Template -> new(filename => "$tmpldir/generic.t +t"); $template ->param( des => $hashref->{'des'}, form => $hashref->{'form'}, action => $hashref->{'action'}, label => $hashref->{'label'}, field => $hashref->{'field'}, value => $hashref->{'value'}, submit => 'submit', if_more => $hashref->{'if_more'}, options => $hashref->{'options'}, ); print $template->output; }
The first template output (the one that prints the list of schools in @options) works fine

With the second template output, I get this error HTML::Template::param() : attempt to set parameter 'options' with a scalar - parameter is not a TMPL_VAR! at test.pl line 117

The error goes away if I include an empty option list as follows:

# template output 2 (changed) # don't print school names my @options = (); %hash ( des => 'Form 2', # field label label => 'Label 2', # name of field field => 'field2', # size of text input field value => '10', submit => 'submit', options => \@options, if_more => 0, );

What's the right way to do it?

Thanks in anticipation :)

Replies are listed 'Best First'.
Re: HTML::Template question - tmpl_if
by blokhead (Monsignor) on Dec 14, 2003 at 01:54 UTC
    I can't reproduce this (Perl 5.8.2, HTML::Template 2.6). Can you verify that even this small test script fails?

    You should only get that error if you are passing something other than an array ref as the "options" parameter.. for instance, if you accidentally misplaced the backslash in options => \@options. I'd take a good look at all the things you pass to $template->param with Data::Dumper

    blokhead

Re: HTML::Template question - tmpl_if
by djantzen (Priest) on Dec 14, 2003 at 01:44 UTC

    Hi kiat,

    The code you posted runs just fine for me, and under strict and warnings to boot. The only way I could elicit the error you describe is by intentionally inserting either undef, a string literal, or an actual scalar in for the value of options. If the key is simply absent -- as in your template output 2 -- then the output looks as it should. There's nothing to iterate over and so no loop contents displayed. Are you positive that's what is actually generating the error?


    "The dead do not recognize context" -- Kai, Lexx
      Hi djantzen,

      Thanks for helping!

      In my attempt to simplify, I left a subroutine out. I've included it in the latest update. The subroutine takes a hash and prepare it for output to HTML::Template.

      I would appreciate very much your taking a look at it again.

      Thanks in advance :)

        Well this is somewhat poor style, but you could say something like:

        options => defined($hashref->{'options'}) || []

        How about a nice map though that only pulls out the defined elements in your hash?

        map { defined $hash->{$_} ? ($_ => $hash->{$_}) : () } keys %$hash;

        The output then can be fed directly into param. This is limited too in that it assumes your hashkeys are identical to your fields (TMPL_VARS), but if you can live with that assumption it might work for you.

        HTH


        "The dead do not recognize context" -- Kai, Lexx
Re: HTML::Template question - tmpl_if
by punkish (Priest) on Dec 14, 2003 at 16:15 UTC
    ok, several comments --

    One, there is an H::T list. If you are going to use H::T a lot (and it would be great if you do), I would encourage you to join the list because the focus of all the members of the list is nothing but H::T.

    repeatedly, in your code you have a trailing comma in while defining your hash. I am surprised you are not getting an error for that.

    %hash ( des => 'Form 2', # field label label => 'Label 2', # name of field field => 'field2', # size of text input field value => '10', submit => 'submit', options => \@options, if_more => 0, );
    that last comma, the one after if_more => 0, should not be there.

    Look at what the error message is saying -- it is telling you that you are trying to set parameter 'options' with a scalar, but that parameter is not a TMPL_VAR. Well, look at your template... 'options' is indeed not a TMPL_VAR but a TMPL_LOOP, and a TMPL_LOOP expects a ref to an array of hashrefs. If you give it a scalar (which, you inadvertently do by not setting a value for options in your second example), the code will croak.

    hth

      Actually perl doesn't mid a bit if you have too many commas in a list, and in fact I've heard monks advocate a trailing comma to make it easier later to expand the list. I avoid doing it myself but mostly for aesthetic reasons.

      use strict; use warnings; my @list = ('foo', 'bar',,,,'baz',,,,); print "Item $_\n" for @list; print "Length " . scalar @list."\n";
      Note that perl even gets the length of the array correct.


      "The dead do not recognize context" -- Kai, Lexx
        I stand corrected. And, I agree with you -- since I have always left the trailing comma out, I will continue to leave it out. Aesthetically it is more pleasing, and logically it achieves a closure. Good for the heart and the mind.
      Thanks, punkish!

      I did a dump of @options.

      # This dumped output of options is #$VAR1 = { 'school' => 'Admiralty Primary', 'school_id' => '1' }; #$VAR2 = { 'school' => 'Ahmad Ibrahim Primary', 'school_id' => '2' }; #$VAR3 = { 'school' => 'Anderson Primary', 'school_id' => '3' }; # the relevant template is # note that the school_id in <select name="school_id"> is # hard-coded whereas the one in <tmpl_var name=school_id>"> # is a number supplied via @options <select name="school_id"><option selected value="1"><option selected v +alue="0">Select<tmpl_loop name=options> <option value="<tmpl_var name=school_id>"><tmpl_var escape=html name=s +chool></option></tmpl_loop> </select></td></tr>
      The above works with the template but I'm not sure if I'm missing something. Note that %hash is passed to &generate (thanks to djantzen for the map) which generates a list which is then supplied to the param of H::T.
        I am not sure what your question is this time around. You write...
        The above works with the template but I'm not sure if I'm missing something.
        If it works, then you are not missing anything. Your template code is, though, a bit confusing. You have typed (perhaps, a typo) --
        <select name="school_id"><option selected value="1"><option selected v +alue="0">Select<tmpl_loop name=options> <option value="<tmpl_var name=school_id>"><tmpl_var escape=html name=s +chool></option></tmpl_loop> </select>
        Perhaps you meant --
        <select name="school_id" size="1"> <option selected value="0">Select school</option> <tmpl_loop options> <option value="<tmpl_var school_id>"><tmpl_var escape=html school> +</option> </tmpl_loop> </select>
        Wrt your original question, no matter how you do it, just remember that in H::T each variable is a scalar, while each loop is an array of hash(es). You'll be ok. If you want to not set anything, you can do one of two things -- turn die_on_bad_params off by setting it to 0, or better yet, make sure you set the value to an empty reference. Actually, you can do one more thing -- use tmpl_if to check for existence of a var before trying to display it. Good luck.