So normally I don't worry too much about completely different templates. Most sites I've worked on will use one main layout with perhaps just a few variations. The inner content may move from two columns to one column perhaps. To handle cases like that, I simply add new attributes to my custom tag to let me specify which to use, and I try to gauge which layout is used most often and make that the default. But how would you handle a case where the layout you want is really varied? As always, there are a few things to consider. One simple way is to just use multiple custom tags. So you may have a productlayout.cfm and a reviewlayout.cfm file. This works ok if your file has a hard coded template. I.e., if you always know foo.cfm is a product page, you wrap it with productlayout.cfm. But again - that's hard coded and won't always be appropriate, especially if you want the layout to be chosen by a non-technical user who doesn't want to edit code. Another possible way of doing this is demonstrated in Galleon. For that project I created a layout custom tag that takes a template attribute. The code for this tag is here:Somewhere about a year ago, I found an article on using a layout.cfm page "custom tag" to layout the template for the site. I include a header, menu and footer. I wrap this around all my pages and volia we have a fairly robust template engine. Only now with all the power of the cfc and a huge whole in my plan, I need a new way to do this layout. I need to be able to create different layouts in the content area, but make them reusable through out the site. With the simple cfcase value="start" and end option I do not have a way to specify the or dynamically call a different layout page without having to write an entire new layout page with that code in there. If that is the best way I can do that but, there has to be a way to make it and I can not wrap my brain around that process.
2 <cfif isDefined("attributes.templatename")>
3 <cfset attributes.template = attributes.templatename>
4 </cfif>
5 <cfparam name="attributes.template">
6 <cfparam name="attributes.title" default="">
7
8 <cfset base = attributes.template>
9
10 <cfif thisTag.executionMode is "start">
11 <cfset myFile = base & "_header.cfm">
12 <cfelse>
13 <cfset myFile = base & "_footer.cfm">
14 </cfif>
15
16 <cfinclude template="../pagetemplates/#myFile#">
2 ...
3 </cf_layout>
2 ...
3 </cf_layout>
Comment 1 written by Todd Rafferty on 6 January 2008, at 9:37 AM
<cf_layout>
<cf_layoutparam attributes... />
<cf_layout>
Then you can keep the layout shell as generic as possible on a page by page basis and if there's an additional parameters that need to be passed in (such as template), then you can pass it in via cf_layoutparam, but it's not required (meaning, layout.cfm has a default mode). The <cfassociate> tag is awesome/fun to play around with. A lot of power you can add to custom tags that way.
Comment 2 written by Todd Rafferty on 6 January 2008, at 9:38 AM
<cf_layoutparam attributes... />
</cf_layout>
Comment 3 written by Raymond Camden on 6 January 2008, at 10:23 AM
Obviously, a VERY small, nitpicky difference of opinion. ;)
I _do_ think cfassociate is cool. Custom tags are under appreciated. :)
Comment 4 written by Todd Rafferty on 6 January 2008, at 10:37 AM
In my Application.cfc, my call to <cflayout> is this:
<cffunction name="onRequest">
<cfargument name="whatever">
<cf_layout><cfinclude template="#arguments.whatever#"></cf_layout>
</cffunction>
Done. Never ever have to touch that code again. On my init pages for my applications, if I need something that cf_layout needs to be aware of, then I use cf_layoutparam to pass in those attributes and I'm done.
Comment 5 written by Todd Rafferty on 6 January 2008, at 10:39 AM
Comment 6 written by Raymond Camden on 6 January 2008, at 11:02 AM
Comment 7 written by John Farrar on 6 January 2008, at 3:40 PM
We call the concept you are refer to here skinning. It's a little more than what the article mentioned and would be pretty hard to cover in a single blog post. I think for simplistic solutions this is about as good as you can get Ray. If your going to take it to another level then it should be a whole framework rather than more of add a piece here and there. This is an excellent article.
Comment 8 written by Joshua Curtiss on 7 January 2008, at 4:45 PM
[Add Comment] [Subscribe to Comments]