ColdFusion Custom Tag Tips
Now a days it seems like every one talks about CFCs, or UDFs, and almost no one talks about custom tags. While they are a bit slower than CFCs or UDFs, custom tags are still pretty darn handy. Here are a few tips for people writing custom tags.
1) Watch your whitespace.
This is more a general ColdFusion tip, but since custom tags tend to be used inside other documents (otherwise they wouldn't be custom tags), you tend to notice their white space even more, especially if the tag is used inside a loop. I recommend just using cfsetting on top and at the bottom of your file, although be sure to also use cfsetting if you leave your custom tag early.
2) If your custom tag is not meant to be used in "wrapped" mode, then always include this line as your last line of code:
<cfexit method="exitTag"%gt;
If you don't, and someone calls your tag like so, <cf_foo/>, then your tag will execute twice.
3) While I may use "cf_" format in my examples, I almost never use cf_ when invoking a custom tag. I use cfmodule. This tends to be a bit more wordy, but it means i don't have to worry about "name" confusion. This is where ColdFusion has to look for your custom tag, and could potentially find the wrong one. Not only that, ColdFusion caches the location of the tag, so if you move it, you need to restart ColdFusion. All of this goes away if you use cfmodule.
4) If you return a value, do not hard code it like so:
<cfset caller.foo = 1>
Rather, make it an attribute so the caller can specify what result to return. For example:
<cfparam name="attributes.result" default="result" type="variableName">
<cfset caller[attribute.result] = now()>
This lets me call the tag like so:
<cf_foo>
<cf_foo result="result2">
<cf_foo result="result3">
At the end of those lines, I'd have 3 variables created: result, result2, and result3.
Comments
I do have one question though. It's about CFmodule Here (CFMX Coding Standards if the link doesn't come through) http://livedocs.macromedia.com/wtg/public/coding_s... Adobe says Don't use CFmodule.
Now this was written By Sean Corfield I believe. If the two of you disgree, I don't know who to believe. :)
In a more answerable question, wouldn't using cfimport achieve your goals without using cfmodule?
That makes sense to me. Thanks.
Being ambiguous on the other hand, was unintented.
For my part, it depends on the application.
When using global custom tags for applications that have a relatively permanent home, I prefer to call custom tags from the custom tags directory using cf_ format.
If I am developing an application with an eye on distribution, I prefer cfimport so that I can specify the location of the tags more precisely.
The main advantage that I see of cfimport over cfmodule is readability and clarity when nesting tags.
(ps. I am not attacking, I am geninuingly interested in this idea)
cfimport: I don't know why, but it never really turned me on. Maybe it's the fact that you must use the import on EVERY file that needs it.
Ben: I can definitely say that non-display custom tags and UDFs are pretty blurred (I mean the differences between them). I tend to keep my UDFs for shorter blocks of logic, while a more advanced logic block would go into a custom tag. Again though, I do -not- have hard rules for it.
I don't know about Ray, but I have had custom tags that are primarily for output (a function well suited for a custom tag) but also need to return variable.
Ray,
I actually felt the same about cfimport until a recent project (that I finished up around the end of the month...) where I wanted to use some custom tags but cf_ syntax didn't have the flexibility.
I tried cfmodule, but it was just ugly as heck. I tried cfimport and found that I didn't like including it on every page, but it was still well worth the trouble (a surprising change of a long-held opinion for me).
<form:tag disableonsubit="true">
<form:doubleselect name="" value="" .... />
<form:dateselectcalendar name="" ... />
</form:tag>
I just think it makes reading and understanding the code soo much clearer.
With cf_, ColdFusion has a set pattern it follows to find the file. I can't direct it to look where I want.
<cfinvoke component="#fooo#">
versus
<cfinvoke component="foo">
The second method will make a new CFC. The first one will use an existing CFC and won't have the startup cost.
That is kinda cool, might have used that tag more but I am one of those guys who likes to do CFScript... so I missed that implementation technique. THANKS!
John: Cool. You love Spry too, right?
I agree - nested tagd are very powerful if used correctly.
Alan
I shall look into this as a future feature
MD
What would you say about referencing request or application variables within the custom tag?
Should all variables used in the custom tag be passed in as attributes?
Nick
I can't speak for Ray, but I would say that using any shared-scope variables from within a custom tag is generally bad form as it break encapsulation.
If you pass them in as attributes, of course, that is OK.
You will find some exceptions. For example, I sometimes use request variables to set defaults for attributes. I do make sure that my custom tags work if none of the request variables exist. I also make sure to name the request variables such that it is unlikely to cause a name conflict (I name put the variables in a structure named for the custom tag).
Thanks for the comments... I typically do the same thing. I like to make sure all variables referenced within the tag are declared and in the attributes scope -- but sometimes will use request variables as defaults.
I'm curious as to what some others think about this and whether it's considered good practice or not.
Nick
/shared/tags/security
/shared/tags/forms
<cfimport ...>
Then your code is no problem. (The benefit of easy to read code compared to CFModule is worth it. You also don't run into conflicts where the extra attributes of CFModule get in the way of your custom tag attributes. Lastly, it works perfect with shared hosting!)
My hope is that they allow us to map some of these things in the next version of CF. Then we can map the tags in our application page, and you and I won't have to do it page by page. We will see.
<cfset myName = "Javier Julio">
Or
<cfset Variables.myName = "Javier Julio">
Is there any benefit with either approach?? Or is it more of unneccessary in a custom tag as maybe a custom tag only defaults to the Variables scope whenever you set a simple var?? A great post with some real useful tips. Keep it up!
As for your notice of me doing a post on CTs - I was a huge fan of CTs for many years. I truly do love em. One of the changes to CFLib will be to support CTs, since the Macromedia Exchange has lots of commercial stuff on it.
Never saw this anywhere else, but I just ran across this tip in the CFMX7 Documentation:
"Tip: To improve performance, avoid using the cfparam tag in ColdFusion functions, including in CFC methods. Instead, place the cfparam tags in the body of the CFML pages."
No problem, I'd never use CFPARAM in a function. But what about custom tags? When this tip says "place the cfparam tags in the body of the CFML pages" is it just referring to simple CFML pages that display output?
I have a custom tag that performs some data validation. I send in the form scope as an attribute collection. Within the body of the custom tag, some of the validation is implemented with CFPARAM.
This tip concerning functions now has me second-guessing that usage. What's the truth concerning perfomance and using CFPARAM within a custom tag?
Thanks!
That being said - I personally don't think there is anything wrong with it - however - I tend to NOT like it when the default value is complex, like a struct:
cfparam name="foo" default="#structnew()#"
The reason is that CF has to run the structNew even if foo already exists. Again though, that should be a very minor speed hit.
I always confuse myself when I read too much.
Thank you :^)
Could any body confirm whether using <cfmodule> will physically include the whole file in to the parent file.
Thanks
The only way a CFC is faster is if you have cached it in a persistent scope, such as application scope so that it remains in memory. Or if you are calling multiple methods on that CFC after it has instantiated within the same request, then it may turn out to be quicker than calling the same custom tag the same number of times.
The slowness of CFC's is caused by the initial instantiation of it, so this is where you need to calculate if any improvements are gained if you are not goign to cache the CFC.
So to be clear.
<cfinvoke component="foo"...>
is slower than
<cf_foo...>
but
<cfinvoke component="#application.foo#"...>
would be faster.
Frankly - you (developer) need to make the choice between CFC versus custom tag based on what you are doing - not which one is 0.001% faster.

