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:
1 <cfset caller.foo = 1>
Rather, make it an attribute so the caller can specify what result to return. For example:
1 <cfparam name="attributes.result" default="result" type="variableName">
2
3 <cfset caller[attribute.result] = now()>
This lets me call the tag like so:
2
3 <cfset caller[attribute.result] = now()>
1 <cf_foo>
2 <cf_foo result="result2">
3 <cf_foo result="result3">
At the end of those lines, I'd have 3 variables created: result, result2, and result3.
2 <cf_foo result="result2">
3 <cf_foo result="result3">
Comment 1 written by todd on 17 August 2006, at 2:05 PM
Comment 2 written by Raymond Camden on 17 August 2006, at 2:09 PM
Comment 3 written by Terrence Ryan on 17 August 2006, at 2:51 PM
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?
Comment 4 written by Raymond Camden on 17 August 2006, at 2:59 PM
Comment 5 written by Terrence Ryan on 17 August 2006, at 3:04 PM
That makes sense to me. Thanks.
Comment 6 written by Raymond Camden on 17 August 2006, at 3:08 PM
Comment 7 written by Terrence Ryan on 17 August 2006, at 3:12 PM
Being ambiguous on the other hand, was unintented.
Comment 8 written by Steve Bryant on 17 August 2006, at 3:13 PM
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.
Comment 9 written by Ben Nadel on 17 August 2006, at 3:14 PM
(ps. I am not attacking, I am geninuingly interested in this idea)
Comment 10 written by Raymond Camden on 17 August 2006, at 3:22 PM
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.
Comment 11 written by Steve Bryant on 17 August 2006, at 3:28 PM
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).
Comment 12 written by John Farrar on 17 August 2006, at 3:32 PM
Comment 13 written by Ben Nadel on 17 August 2006, at 3:32 PM
<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.
Comment 14 written by Raymond Camden on 17 August 2006, at 3:32 PM
Comment 15 written by Steve Bryant on 17 August 2006, at 3:37 PM
With cf_, ColdFusion has a set pattern it follows to find the file. I can't direct it to look where I want.
Comment 16 written by Raymond Camden on 17 August 2006, at 3:38 PM
<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.
Comment 17 written by John Farrar on 17 August 2006, at 3:39 PM
Comment 18 written by John Farrar on 17 August 2006, at 3:41 PM
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!
Comment 19 written by Raymond Camden on 17 August 2006, at 3:41 PM
John: Cool. You love Spry too, right?
I agree - nested tagd are very powerful if used correctly.
Comment 20 written by John Farrar on 17 August 2006, at 3:42 PM
Comment 21 written by Raymond Camden on 17 August 2006, at 4:26 PM
Comment 22 written by Alan on 18 August 2006, at 9:34 AM
Alan
Comment 23 written by Mark Drew on 18 August 2006, at 12:12 PM
I shall look into this as a future feature
MD
Comment 24 written by Nick on 19 August 2006, at 10:56 AM
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
Comment 25 written by Steve Bryant on 19 August 2006, at 1:25 PM
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).
Comment 26 written by Nick on 19 August 2006, at 2:28 PM
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
Comment 27 written by John Farrar on 19 August 2006, at 3:29 PM
/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.
Comment 28 written by Raymond Camden on 19 August 2006, at 7:22 PM
Comment 29 written by Raymond Camden on 19 August 2006, at 7:25 PM
Comment 30 written by Javier Julio on 21 August 2006, at 2:15 PM
<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!
Comment 31 written by Raymond Camden on 21 August 2006, at 3:08 PM
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.
Comment 32 written by Javier Julio on 21 August 2006, at 3:13 PM
Comment 33 written by Carry on 25 September 2006, at 1:42 PM
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!
Comment 34 written by Raymond Camden on 25 September 2006, at 1:45 PM
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.
Comment 35 written by Carry on 25 September 2006, at 1:51 PM
I always confuse myself when I read too much.
Thank you :^)
Comment 36 written by Raymond Camden on 25 September 2006, at 1:56 PM
Comment 37 written by praman on 3 October 2006, at 1:45 AM
Could any body confirm whether using <cfmodule> will physically include the whole file in to the parent file.
Thanks
Comment 38 written by Raymond Camden on 8 October 2006, at 9:35 AM
Comment 39 written by Russ Michaels on 1 November 2007, at 6:22 PM
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.
Comment 40 written by Raymond Camden on 1 November 2007, at 7:50 PM
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.
Comment 41 written by Russ Michaels on 1 November 2007, at 8:20 PM
Comment 42 written by Arowolo M.A on 19 April 2008, at 7:47 PM
Comment 43 written by Richard on 9 September 2008, at 6:34 AM
I am not sure whether I am missing something but have you posted the link to the Custom tags guide? I would grateful if you can guide me to where it is.
Thanks
Comment 44 written by Raymond Camden on 9 September 2008, at 8:17 AM
[Add Comment] [Subscribe to Comments]