I've been using HTML::Template for quite a while now. It has helped greatly in moving a lot of html (and sometimes logic, as when using tmpl_if) out of my code. The result is a more readable code as well as separation of code and html.
When the layout is simple, such as pulling rows of data from a db and displaying them on an html page, it's trivial to achieve a clean separation of code and html.
However, when the page's layout involves quite a bit of logic, I find it sometimes difficult to filter out the html from the code. What I tend to do in such cases is to build up an html string, and then feed that string, together with other tmpl outputs, to the template file.
Do you have that sort of problems? Or are you able to always cleanly compartmentize code and html? I would love to hear from you :)
Thanks in anticipation.
Update: Many thanks to all for sharing :)
It appears the majority find it always possible to separate the program code from the html. There's however some support for the inclusion of html in the code in cases where their separation proves difficult or impossible (in the eyes of the beholder).
Update2: Reading some of the comments, it seems that it's quite common to move the logic from the Perl code to the template (nodes 367304, 367252). amw1 says it's display logic vs processing logic. So it appears to me that some mixing of code and html is inavoidable. It's where that mixing takes place. If part of the logic is moved to the template, then you inevitably have a more complicated template. If the (display) logic resides in the Perl code, then you inevitably have a more complicated Perl code. So perhaps it's a matter of which type of complication you are more comfortable with?
What I tend to do in such cases is to build up an html string, and then feed that string, together with other tmpl outputs, to the template file.I just give TT a bunch of scalars, arrays and/or hashes which I want to present in HTML, and let the templating engine deal with that. Arjen
like default values of variables
One of the problems I find when making pages with lots of interactivity is that you want to make "subroutines" that create parts of the HTML.
Example: in a CMS that I'm making - yes, another one - I have a page that lists the document tree, with "nieuw" links that open the editor for a new page. These links can be put on several parts of the page. To simplify this, i made a BLOCK, like so:
[% BLOCK new_page %]Here, the page items are [cpan://Class::DBI] objects. Now, whenever I want to to show these links, I do:Nieuw [% END %]
[% IF form.action == 'new' %] [% INCLUDE new_page page=some_page span=2 %] [% END %]
TT uses the same syntax to include other templates, so if needed, I can move the BLOCK to a seperate file without having to change the calling code.
By the way, I use a seperate hash-ref "form" to store the values I want to set in the form on the editor.
This $form hashref is initially filled with the values from the CGI request, but it allows me to change the values in "form" (for instance, with data from the $page object from the database) but still have the original request object lying around if I need it. This is a nice seperation of concerns that is very much used in [http://jakarta.apache.org/struts/|the Struts java MVC framework], and works pretty well for more complicated interactions.
this takes a scalar and a list or scalar. If the scalar matches the other scalar or matches a value in the list the macro resolves to "selected" otherwise it does nothing. (used to find selected values in a <select> list.
[%
# sets selected if both values match
# tries to see if either side is an array to try and find a match
# out of an array of possibly selected values. This will work for multiple
# select lists.
%]
[%- MACRO is_selected(val1, val2) BLOCK -%]
[% IF val1 == val2 %]
selected
[%- selected = 1 %]
[% END %]
[% IF !selected %]
[%- FOREACH value = val1 -%]
[%- IF value == val2 -%]
selected
[%- selected = 1 -%]
[%- LAST -%]
[%- END -%]
[%- END -%]
[% END %]
[%- IF !selected -%]
[%- FOREACH value = val2 -%]
[%- IF value == val1 -%]
selected
[%- LAST -%]
[%- END -%]
[%- END -%]
[%- END -%]
[%- END -%]
This lets you do things like. . . .
[% # selected items is a list of what should be selected # from this list %]I have not seen anything in HTML::Template that will let me come close to being able to do this. Most of the work that the template is doing would have to be shifted into the perl code. with html::Template (afaik, I stopped using after I got approval to use TT). In the above example option_list is a hash (that for sake of argument I got from a library call that I don't control). In H::T I'd have to re-write that structure into an array, I'd also have to resolve the selected attribute inside the perl code. The only place where those things are needed are for the display, so why should they be in the perl code.
Granted, there is logic in the templates now, but it is solely DISPLAY logic. It is not processing logic. The split I try to get is to not have ANY display logic in the perl code and to not have ANY processing logic in the template. Stuff like properly formatting a date gets put into the template. Stuff like cooking data before it is put into the database lives in the perl code. There seems to be a fairly large camp that does not want to put any logic inside the templates. They are right too. :)
Sorry if this is a bit long winded but I really enjoy working with this stuff.
[% mycgi.popup_menu( '-name' => 'mylist', '-values' => [ 1,2,3 ], '-default' => 2 ) %]i used that all the time when i was using TT. let the CGI.pm plug-in do its job.
Once you understand wht is the data structure, HTML::Template is really in your favour - you can create nested loops, ifs and includes. The problem is when you want to do something like taking a simple loop and print it in two columns, and then the design of the page will reflect in your code (I did this by creating a loop of rows inside a loop of collumns). I don't know if that's considered clean enough for you, but it's batter, IMO, than printing raw HTML, since the visual design is still left to the template
A related question is printing CGI fields: put them in the template or create them with CGI.pm? I mean:
vs just
The answer depends on the complexity of the field (a hidden field is easy to put in the template, a dynamic n-level menu isn't) and the overall level of seperation you decided on - I usually separate as much as I can. Just look at it from the design / logic point of view: "Do I have to know what widget gave me this value?" usually not. Mostly you just have to know if the value is single, multiple choice, etc. but not how it got there.
Hope this helps
perl -e'$b=unpack"b*",pack"H*","59dfce2d6b1664d3b26cd9969503";\ for(;$aMy public key
So, I beleive that with the correct analysis, and pre-design, you can always seperate the two.
This community thrives because there are enough people with questions (good, bad or ugly) and even more people who not only have the knowledge but are willing to spend a little of their precious time to help and to share the knowledge.
Thanks for your feedback! It's very encouraging :)
I can't validate my code in BBEDIT because it stumbles over all the H::T stuff. A bit frustrating
HTML::Template allows you to put your TMPL_VAR, TMPL_LOOP, and other directives inside HTML comments, e.g. is the same as
HTH
The template directives are removed before the page is actually sent over the network, so I don't see how it would have any effect on bandwidth, one way or another. As for the comment in the POD about "dramatic savings in bandwidth," I believe they are making a joke. The size of the POD would be dramatically smaller without using comment-style directives, thus saving huge amounts of bandwidth transmitting the documentation.
Update: for what it's worth, when I wrote my first reply, I did miss the part of your original post where you mention the comment-style directives. I apologize for that, but hopefully this post will reassure you of their use in the future.
One thing I used to do, for putting results in pages, was to provide my data to a display object, and have the display object do all the heavy work of either just doing a straight template->render() call (we used a custom template solution like HTML::Template), or populate certain parts based on the data.
The other solution, is to use a "stronger" template engine. HTML::Template is great if you do the above. But things like TT or using XML::XSLT (i like this one) leaves you better off. With XML::XSLT, at least your template language is more universal. Some XSLT implementations aren't as complete as others, but the basics usually are.
Bart: God, Schmod. I want my monkey-man.
with a bit of thought, i've found that it's always possible to seperate the business logic and display logic using HTML::Template. (at least it has been for everything i've written for the last 3 or 4 years).
you may need to spend a bit of time coming up with a decent solution, but it almost always pays off. eg, i used to resort to using CGI.pm's popup_menu() to produce <select>s and then just passing them in as html strings. eventually i sat down and thought up a better solution and the result has been cleaner code with more control in the hands of the designer.
also, don't be afraid to subclass HTML::Template and override parts of it. that road has many interesting possibilities.
The basic idea is that you design a model, which is a set of object that represents your data in data-centered way - disregard the need for display code.
Then you have a controller, which performs user actions on the model, like adding items, performing calculations, and so forth. It should be pretty thin, and if you find yourself doing too much logic in the controller, that has to do with the contents of the data instead of the contents of the user request, you should probably refactor your model so that it's objects know how to apply this logic to themselves.
Lastly, you have the view, which accept a data model with is view oriented. It cares about display logic only. The controller is responsible for creating objects that are intuitive for the view, from objects that are intuitive to the data model.
I like using the Petal templating system for views, which is similar to HTML::Template, because it's very limited in terms of logic - you have to insert a real object model into it (as objects, or nested data structures), you don't get much more than if-else. It also looks kind of like H::T, because the templates are valid XHTML themselves.
In contrast to H::T it i a bit easier to use simple logic to create more fine grained HTML output, so I've yet to need to create HTML strings in the perl code.
If you are hard enough on yourself, refactoring your objects often, as annoying as that is, and keeping all the view logic simple, but not letting it in the perl code at all, you usually have much more maintainable code. Rereading stuff like Apache::ASP code is something I really don't enjoy, because Perl and HTML are mixed freely.
Another thing you should look at is Maypole - it's purpose is to bring MVC to web programming, and let you build web UIs very easily and quickly. It's new, so it's still under heavy development, but if you don't like it most the discussions about it notes the nice set of alternatives that are available.
Given that, if your templating system doesn't have all the features you need, then maybe it's time to use a different templating system. We're actually going to be doing that in the next six months.
With proper tools and adequate design time, it is always possible to accomplish a clean MVC separation.
------
We are the carpenters and bricklayers of the Information Age.
Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose
I shouldn't have to say this, but any code, unless otherwise stated, is untested
. . .And I've never looked back since. It takes some work sometimes, but my content and program logic are entirely separate now. I can hand my designer blank template files, write my programs, and know they will work perfectly and look great when the templates come back.
How do I do it??? Liberal use of some of the more advanced features of H::T, lots of TMPL_IFs, TMPL_VARs, and TMPL_LOOPs, and the good ole' conditional operator ;) I'm not saying this is the best way, but it works well for me.
Here's a brief example of what I do. First, the template:
Parcel Number
|
Name
|
Address |
$tmpl_results->param
(
RESULTS => \@results,
SESSION => $config{USE_SESSION_HACK} eq "Y" ? $self->param("session")->id : "",
SCRIPT => $request->url,
SORT => $sort,
PARCEL_DIR => (($sort eq "parcel" and $dir eq "ASC" ) ? "DESC" : "ASC"),
PARCEL_ASC => (($sort eq "parcel" and $dir eq "ASC" ) ? "Y" : ""),
PARCEL_DESC => (($sort eq "parcel" and $dir eq "DESC") ? "Y" : ""),
NAME_DIR => (($sort eq "name" and $dir eq "ASC") ? "DESC" : "ASC"),
NAME_ASC => (($sort eq "name" and $dir eq "ASC" ) ? "Y" : ""),
NAME_DESC => (($sort eq "name" and $dir eq "DESC" ) ? "Y" : ""),
DIR => $dir,
TIME => sprintf("%$config{FORMAT_TIME}", $time),
NUM_RESULTS => $rows,
START => $first,
END => $last,
FIRST => ($first == 1 ? "" : "first=1&last=$config{INCREMENT}"),
PREV => ($first == 1 ? "" : "first=" . ($first - $config{INCREMENT}) . "&last=" . ($last - $config{INCREMENT})),
NEXT => ($last >= $rows ? "" : "first=" . ($first + $config{INCREMENT}) . "&last=" . ($last + $config{INCREMENT})),
LAST => ($last >= $rows ? "" : "first=" . ($rows - $config{INCREMENT}) . "&last=$rows"),
);
One thing that has drastically helped my development is [cpan://HTML::Template]. It promotes cleaner application structure, and plays nicely with H::T. Give it a check.Feel free to contact me with questions about what I did.
Cheers!
MrCromeDome
if ($u_level == 0)
{
$bgcolor = "#FF0000";
}
else if ($u_level == 1)
{
$bgcolor = "#0000FF";
}
# tons of code...
print<<
DaWolf's silly example
HTML;
Second way (mixing logic and presentation):
# tons of code... print<<The advantage of the second way in my point of view is that you don't need to go all the way up to understand what $bgcolor means and why it have this or that value, so the code is more easily understandable and more practical to debug.DaWolf's silly example HTML1; if ($u_level == 0) { print ""; } else if ($u_level == 1) { print ""; } print<<HTML2;
I can see $bgcolor and know exactly what it means. Same with any other well-named variable. That aside there are tons of problems with your approach
No offense intended and I understand its your opinion, however your suggestion is the exact opposite of what the parent poster is trying to accomplish. So its not exactly helpful. Also try some templating, trust me, its not hard (I personally like H::T!) and once you get it you'll never ever go back!
Update: Fixed some typos and my terrible spelling :)
I used to do it that way. There's a lot of html in the code. In the long run, it might be better to move the bulk of the html to a template.
You might want to seriously consider something like HTML::Template. I started using it at the beginning of this year and there's no turning back.
I've moved out lots of html from the code into the templates, and it makes for a cleaner code and probably an easier maintanence task.
What I find difficult and sometimes impossible to achieve is a 100% separation of code and html. But as others have pointed out, it's doable with a clear idea of the program logic. With time and more practice, I might be able to do that.
On a different note, I've seen rather huge programs (ikonboard and yabb) with code and html glued together.
cheers
my @colors = ('#FFFFFF', '#F0F0F0');
my $cnt = 1;
foreach my $row (@$list) {
$row->{bgcolor} = $colors[$cnt % 2];
# Assign $row to your template engine or AoH or whatever...
$cnt++;
}
create a block macro
[% MACRO alt_color(loop_count) BLOCK %]
[% IF loop_count % 2 == 0 %]
color1
[% ELSE %]
color2
[% END %]
[% END %]
in your template you do
loop.count is a special property of the iterator
[% FOREACH thing = things %]
[% thing %]
[% END %]
for H::T you can do
you need to make sure you have loop_context_vars set to 1 in H::T to have access to __ODD__/__EVEN__ color color2> thing
If you only speak of two colors, it's quite easy in the template system I use (and I guess, even easier on standard Template systems).
I create an array (call it @array) on my perl program, containing hashes. One of the hash elements is named "bgcolor" and is actually a boolean value. Let's say for example that it also has a "content" value which is string and a "cnt" value which is integer (a counter).
The code notation provided works for HTMLTP, but it should work anywhere as the logical part.
| [:cnt:] | The content of the [:cnt:]th element is : [:content:] |
I guess I could add it ;)....
....
It is not so easy to avoid what is known as scattering and tangling. Here is a good paper on separation of concerns in web apps, suggesting an AOP approach.
Speaking of AOP, there is a new developer release of the Aspect module.
I wrote a (yet unpublished to CPAN) module called "QWizard" that lets you write "wizard" screens that do complex sets of interrelated web pages easily. You define your questions to ask of the user (or things to just display, whatever) and code that acts on those questions (perl). When you write it using the generic widget building set (HASH descriptions), it will display it for you. We have used no HTML in the GUI part of net-policy, which is where these modules live currently, and the result is that the interface works under both HTML and Perl/tk without modification. new backends can be done at will as well (I have a half-working curses version). but, you have to conform to "how the screens are intended to look" (though its really flexible).
The advantage of Qwizard in particular is that you can write a CGI script that works asa HTML display when run from apache, and the same script when executed from the command line runs as a TK window without any modification...
I come down firmly in favor of keeping code out of templates.
The project I'm on now assembles HTML hierarchically, using HTML::Template-based fragements to assemble larger pages. This lets us build reusable components while still keeping our HTML separated from our code. Consider something like:
Here somes a table
On first glance, you might assume that table is a chunk of HTML table tags generated from code, but nothing says that it can't be the result of expanding a different template and stored the resulting HTML in a hash that gets used when constructing arguments for the outer template.
An example of this was date formatting. All of our routines that get data structures from the database/files/aether etc. return times as seconds since epoch. Much of our backend code makes use of this number without ever converting it. In fact, the only time we ever need to cook that number is when we display it. After cooking the date in the cgi and passing it to the template I started to think that it made no sense to do this work inside the CGI as it had nothing to do with the actual work of the CGI. i.e. the cgi was no longer agnostic wrt how the data was displayed.
After spending some time thinking about this I started to draw the following lines:
The only time I end up breaking this is for things that make a ton more sense to do in a langauge other than the template. (i.e. heavy data manipulation etc) but I try like the devil to code my way around that.
It may have been my lack of experience with H::T but I found myself having to re-form many of the data structures we were using into AoH's for use by H::T. With TT I was able to use whatever datastructure I wanted to pass to the system. Again, this lead to a bit more logic in the template, but it was for display only. Using the cgi to reformat data for the template seemed like a huge waste of effort. Granted, we could have re-formed the datastructures from the backend but there were more places where it made sense for us to use straight hashes than AoH's. Since H::T (to my knowledge) won't process a hash I had to spend more time writing code in the CGI that ultimately did nothing but format data for display.
my .02
I am suprised no one has really recommended Text::Template written by Mark-Jason Dominus. The best thing about this module is the templating logic is Perl, not some made up something else to learn.
I like to break out my display logic into a separate file, so I have code, display logic, and template. The template only contains output variables (so webdesigners don't have to mess with logic elements) and it gives me the power to change the template based on display logic. So I can deliver HTML, plain text, XML or whatever, I can also internationalize output easily with this method.
Not far off in degree of separation is Petal.
perlmonks.org content © perlmonks.org and amw1, Anonymous Monk, Aragorn, artist, bradcathey, cfreak, davis, DaWolf, dragonchild, dws, elwarren, eserte, exussum0, geektron, gwhite, injunjoel, Joost, kiat, metaperl, Michalis, MrCromeDome, mvc, nothingmuch, revdiablo, saberworks, thraxil, yosefm
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03