I was just reading a post on Seth Duffey's blog about using ColdFusion custom tags to output common headers and footers.
Although I don't disagree using custom tags for reusable logic (and layout), I don't totally agree with his method for the situation he setup.
In his example he wanted to express that using an include tag to output his header and footer did not allow him to pass variables to the included file (not without setting some global variables). So his solution was to make a custom tag and to output it using the following format:
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<cf_mytag myvar="someValue">
1<cf_mytag myvar="someValue">
The problem I have with this is that in order to call the file I have to either have it in my global custom tags folder (or one that I have setup in the ColdFusion administrator) or I need to have the file in the same folder as the calling file.
Using the traditional format <CF_myTag> does solve many needs; however CFMX has two tags that can help alleviate many headaches when using custom tags.
Solution 1: CFMX 6.0 introduced a new ColdFusion has a tag called
<cfmodule>. Using this tag solves both of Seth's needs in one tag. It allows you to include the file using a relative or absolute path (not physical path), and it allows you to send custom attributes to the file. It also allows you to send a collection of key-value pairs using the
attributeCollection attribute. Once the file has been called it follows the rules of a custom tag (i.e. attribute variables are referenced with the attribute scope, local variables set on the calling page are protected, etc).
Using the same scenario Seth setup for us (header/footer) here's an example of the <cfmodule> tag:
(index.cfm)
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<cfmodule template="/tags/skins/header.cfm" title="My Page Title" css="css/demo.css">
1<cfmodule template="/tags/skins/header.cfm" title="My Page Title" css="css/demo.css">
Solution 2: CFMX 6.0 introduced the
<cfimport> tag. This tag allows us to import an entire directory or .cfm files and have them referenced as a library. This is very useful because we don't have to set anything up in the ColdFusion administrator (rather it can be setup in the project and thus allow the project to move from dev to server with ease).
The below example shows the <cfimport> tag importing a skin library and then outputting the data as a header (while still sending custom attributes to the custom tag). Then after some basic content I call the footer tag to output the footer:
(index.cfm)
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<cfimport taglib="/tags/skins" prefix="skin">
<skin:header title="My Page Title" css="css/demo.css" />
<skin:bodyWrapper>
Body content goes here.
</skin:bodyWrapper>
<skin:footer myAttribute="My Custom Value" />
1<cfimport taglib="/tags/skins" prefix="skin">
2
3<skin:header title="My Page Title" css="css/demo.css" />
4<skin:bodyWrapper>
5 Body content goes here.
6</skin:bodyWrapper>
7<skin:footer myAttribute="My Custom Value" />
Notice something different there? I wrapped the body content in the bodyContent custom tag (bodyContent.cfm). This technique is nothing new; rather I am just using the thisTag scope found in the custom tag. I generally use this when I want to wrap certain code around something. An example that might fair well here is:
(/tags/skins/bodyWrapper.cfm)
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<cfif thisTag.executionMode eq "start">
<div id="body">
<cfelse>
</div>
</cfif>
1<cfif thisTag.executionMode eq "start">
2 <div id="body">
3<cfelse>
4 </div>
5</cfif>
There are actually a few other ways we could handle this. But for skinning a site using a custom tag, these are my favorite methods. As I said before, I really do like ColdFusion custom tags and I use them quite often when they are needed. But for skinning sites (such as headers and footers), I really think that <cfmodule> and <cfimport> are choices often overlooked.
http://www.macromedia.com/v1/cfdocs/CFML_Language_...
While I mainly focused on using the custom tag approach I also (briefly) mention using cfmodule:
http://www.leavethatthingalone.com/examples/cfhead...
I think both the custom tag and cfmodule have advantages. I think one of the big advantages of the custom tag approach is that you can setup a custom tags folder and never have to specify the location of your files. The custom tag always looks the same and moving calling templates doesn’t change the tag. That is great for simplicity.
That being said if you want to make a portable application or an app you are sharing, cfmodule might be better because you don’t need to have that custom tags folder and you always specify exactly where your files are.
This example was aimed a specific group who had asked me to post an example, they happen to be beginner CFers and I thought the cfimport approach was a little advanced.
Bringing up the cfimport approach is great, I think a more in depth cfimport example would be great for someone to do.
> I think one of the big advantages of the custom tag approach is that you can setup a custom tags folder and never have to specify the location of your files.
Agreed. Because I have collected so many useful custom tags over the years I like to keep my global custom tags folder restricted to just tags I know will be used by multiple applications. Whereas I leave custom tags specific to that application (like a header or footer) restricted to the application itself.
This approach is nothing new and many frameworks go by this method. But again, to a person new to ColdFusion we sometimes don't want to even mention the word "framework" for fear of losing them entirely :).
One other thing to note is that cfimport and pfx:tag is the fastest option, cf_tag is the next fastest and cfmodule template="/path/to/tag.cfm" is the slowest. This may be surprising but apparently CF does caching on the custom tag paths which makes it faster than the file lookup it needs to do for cfmodule. It's only a minor performance difference but it's something I like to point out simply because it is somewhat surprising!