I am aware of the fact that something of the same subject has recently been posted at PerlMonks. I am also aware of the fact that people have written many texts about this subject, both at PerlMonks and many other places. Also am I aware of the fact that this node possibly does not tell you something new.· Introduction
The main reason for writing this, was that I was thinking about HTML::Template and it's idea and I felt I needed to share my thoughts with others.
So, thank you in advance for reading my thoughts.
Recently, I read the documentation of HTML::Template. I think the idea behind this kind of modules is rather interesting, although sometimes not too consistent.· No HTML tags should be in the Perl code
To truly separate logic and design,
- no HTML tags should be in the Perl code, and
- no logic should be in the HTML template
Well, the first thing is not too difficult: while writing your Perl code, just imagine that readers of your page should be able to read it with interpreters of any mark up language. Imagine HTML::Template could be LaTeX::Template, POD::Template, Man::Template or whatever else template as well.· No logic should be in the HTML template
Of course, a little logic is allowed, for example to create rows that have different colors (the odd numbered rows are white, the even numbered rows are grey) and such things. Just not too many logic.· Let's have a look at PerlMonks
No, I am not going to critizise PM. I was just thinking how PerlMonks would be written if it would use HTML::Template (does it, actually)? For example, let's have a look at the nodelets column.· One way
PM offers a couple of nodelets, all of which have other contents (XP Nodelet: only text; Personal Nodelet: links which the user can specify, chatterbox: text and a form, voting booth: a form).
Not only are users able to choose which nodelets they want to see, also they're able to choose in which order the nodelets will be shown.
The very easiest way of implementing this, is to just create a loop in the HTML template, that uses only two variables: nodelet_title and nodelet_contents. The contents, in this case, will contain HTML tags to create the links and forms and such. So this violates the first rule.· Another way
This way, if you want to create a new nodelet, you only have to modify the Perl script. The template will automatically accept the new nodelet because it will get the title and the contets just in one of the iterations of the loop.
Another way is to create a loop which will get the nodelet titles. Then, for every title you make an if-tag and within the if-tag, the proper variables are retrieved (eventually with the use of loops (within loops (within loops))).· Conclusion
This moves the design issues to the template. Also, it moves much of the logic to the template. Besides, if you want to create a new nodelet, both the Perl code and the template need to support the new nodelet.
I think it is never trully possible to separate design and logic, unless with a fairly simple interface where everything will be as the coder and/or designer wants it to be. Whenever it gets more complex (more customizable for instance) it will become harder to separate the two.Update: fixed some typo's and grammar errors. Thanks to injunjoel
No HTML tags should be in the Perl code
This is a nice dream. However, HTML won't allow it. The best example is in specifying an option in a select list:
If HTML allowed you to make the selection in the select tag itself (like ), then this wouldn't be a problem. As it is, there are numerous ways to solve the problem, none of which are particularly satisfying.
I haven't looked at XForms much (though I like what I have read about it), so I'm not sure if it fixes this problem.
----
send money to your kernel via the boot loader.. This and more wisdom available from Markov Hardburn.
Yes, you can do it that way, and many people do. It makes the templates really, really ugly. If there is a clean solution to this, I haven't seen it yet. Ironically, some of the cleanest ones I've seen involve creating the HTML on the Perl side (though usually with a backend module doing the actual HTML generation).
----
send money to your kernel via the boot loader.. This and more wisdom available from Markov Hardburn.
It makes the templates really, really ugly.
Depends on how you do it. Myself, I use Template Toolkit and right off the bat I created a widgets/ directory in my base template directory. This widgets directory contains a different template for each of the form fields (text inputs, textareas, radio buttons, select fields, etc). My select field template is exactly what is below. I'm not even sure now if the SET option.selected = '' line is needed. I think I had to add it because of some weird complication (perhaps the option.selected value wasn't being reset in each iteration of the loop?).
[% USE HTML %] [% DEFAULT size = 1 %]
Now within any html template that wants to include a select field, all it takes it this simple include:
[% INCLUDE widgets/select.tmpl
name="fav_flavour"
selected="$fav_flavour"
options=[
{ value => 'Chocolate', label => 'brown stuff' },
{ value => 'Vanilla', label => 'plain stuff' },
{ value => 'Strawberry', label => 'red stuff' }
]
%]
Myself, I use Template Toolkit . . .
Increasing the complexity of the template isn't a real solution, because at that point you're no longer doing seperation of data and code, which is the whole point.
----
send money to your kernel via the boot loader.. This and more wisdom available from Markov Hardburn.
Is that really so ugly?
I was thinking of the situation where the HTML designer wanted to include the list statically:
Belch!
----
send money to your kernel via the boot loader.. This and more wisdom available from [http://grenekatz.org/cgi-bin/MarkovBot?id=hardburn|Markov Hardburn].
In this case, i don't think you should allow the designers to do that. Why? Have to answer that one with another question: Why do they need to do that? I'll wager they have no valid, good reason for it.
Many moons ago, samtregar gave me a good piece of advice. There he pointed me to H::T FAQ #11, and since Sam said it much better than i can, i will reprint his text here:
Q: What's the best way to create a <select> form element using HTML::Template?A: There is much disagreement on this issue. My personal preference is to use CGI.pm's excellent popup_menu() and scrolling_list() functions to fill in a single <tmpl_var select_foo> variable.
To some people this smacks of mixing HTML and code in a way that they hoped HTML::Template would help them avoid. To them I'd say that HTML is a violation of the principle of separating design from programming. There's no clear separation between the programmatic elements of the <form> tags and the layout of the <form> tags. You'll have to draw the line somewhere - clearly the designer can't be entirely in charge of form creation.
It's a balancing act and you have to weigh the pros and cons on each side. It is certainly possible to produce a <select> element entirely inside the template. What you end up with is a rat's nest of loops and conditionals. Alternately you can give up a certain amount of flexibility in return for vastly simplifying your templates. I generally choose the latter.
Another option is to investigate HTML::FillInForm which some have reported success using to solve this problem.
For me, this means that you (the HTML designer) give me the list you want and i will make the select for you.
jeffa
L-LL-L--L-LL-L--L-LL-L-- -R--R-RR-R--R-RR-R--R-RR B--B--B--B--B--B--B--B-- H---H---H---H---H---H--- (the triplet paradiddle with high-hat)
Select lists are simple to populate using HTML::FillInForm. Templates get cluttered up very quickly if you try to fill in forms using template tags. They also become much harder to validate (eg " />). Also, if you allow the code to generate the form fields, then you remove the ability of the template designer to change the form fields.
You may argue that HTML::FillInForm needs to have some HTML code in it in order to be able to fill in the HTML form. But it is effectively doing the same thing as a template parser, searching through the HTML for tags that it recognizes (ie HTML form fields), and altering them by assigning a value to the form field. It in no way limits what the template designer can do with the template (ie a select list could be replaced with a series of radio buttons without requiring any code changes, and without needing to alter or adjust any template tags for that matter).
Of course HTML::FillInForm doesn't actually generate the form fields for you, but that is really the job of the Template anyway. In my templates I always try to statically define my form fields unless an option list is dynamically generated by the code. Then a simple loop will do (remember, there will always be some logic in your templates, but it should be display logic only).
Separating code and HTML is easy. You just need to find the right toolset that works for you...
- Cees
I think it is never trully possible to seperate design and logic
IMHO, you should take care to differentiate applicative-logic and GUI-logic, and consider 3 abstraction layers:
+-------+
| Users |
+-------+
^
|
v
+------------+ +-----------+
| HTML-Datas |-->| GUI-logic |
+------------+ +-----------+
^
|
v
+-------------------+
| Applicative-logic |
+-------------------+
^
|
v
+-------+
| Datas |
+-------+
Pro: Design and logic are separated.
Cons: You'll have to stricly follow the rules of responsability separation when developping the differents layers. Anyway, you'll have a bit more code to produce and support all caveats involvde (more code => more bugs => more tests required => less time).
This kind of slicing gives you the basements to build applications decribed as 'Model-View-Controller' in Design-Pattern litteracy.
Updated:corrected some typos and added schematic.
____
[id://262941|HTH], Dominique
My two favorites:
If the only tool you have is a hammer, you will see every problem as a nail. --Abraham Maslow
Bien faire, et le faire savoir...
Same sentiment here. Basically, the options are as follows:
1) no attempt at separation - the perl script contains both code and html
2) some attempt at separation - part of the logic is moved to the template
3) strict separation - no html in code
(3) gives you clean and highly maintainable code but is hard to achieve in some cases. I've been through (1) and the result is ugly and difficult-to-maintain code (which has lots of html in it). (2) seems like a neat solution :)
By the way, I would make each nodelet a separate included template, and just pass a list of nodelet templates to include.
You could also drive your "nodelet_title" / "nodelet_contents" method within a Nodelet class, which, when subclassed, fills nodelet_contents from its own private template file.
So you end up with a top-level display module, and each of the "objects" contained within are able to generate their own contents, possibly through their own templates. I am currently using this, am able to keep the logic and display seperate, and have not run into too many problems.
Most of y problems come down to data structures, and shifting between structures for the program and structures for the display (H::T) has been reduced to a couple of translation routines.
My best experiences have been with Model 2's where:
my $t= HTML::Template->new( $sometemplate ); my $insert = $q->table ( $self->build_some_table ); $t->param ( bigtable=>$insert );This is obviously a naff example, since $insert should be a TMPL_INCLUDE (if you talk HTML:Template).
As raised earlier , display logic within templates is seen to be a necessary evil, less important that seperating WHAT data should be rendered as opposed to HOW that data should be presented. Your code should build valid structures of data that make sense to your templating system.
What this suggests to me is that there is room in the design for a pre-output process between generating valid data and filling a template with that data. When I find myself writing objects with a data struct one way, but a method to output something that makes sense to a template system. eg
my $self = Some::CGI::Class->new( %params ); $self->update_data; return $self->template_data;It feels like the reformatting of my object's data for a template system is NOT the responsibility of my object. There ought to be a preprocessing phase. Yet another level of complexity. This pre-processing stage is where I would expect the addition of things like odd/even line BG color changes, or turning a structure inside out to list it as entities by sorted key. For example , your method returns an hash of object references with names as keys that are valid and relevant to the current application's run_mode, you pass that data structure to a template preprocessor because you would like the data ordered by keys and flattened into an array of hashes suitable for a TMPL_LOOP. MIght look more like.
$self->update_data; my $t = HTML::Template->new( $sometemplate ); my $tpp = HTML::Template::PreProcessor->( hash=>'sorted' , style=>'array' , object=>$self ); $t->param ( $tpp->preprocess ); return $t->output;
perlmonks.org content © perlmonks.org and BUU, cees, dfaure, hardburn, jeffa, kiat, l3nz, MidLifeXis, muba, perrin, saskaqueer, submersible_toaster, thraxil
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03