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

Good tips here. It would be nice to have a quick guide for custom tags. Does one exist somewhere?
# Posted By todd | 8/17/06 2:05 PM
I could hit the little Print button and add ot my guides. Actually, I can just add the link. Count to ten and it will be there.
# Posted By Raymond Camden | 8/17/06 2:09 PM
Thanks, Ray. This is really valuable to those of us that are considering reevaluating the way they do encapsulation.

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?
# Posted By Terrence Ryan | 8/17/06 2:51 PM
In general I rank Sean's skills over mine, but I'll disagree here. I believe he was worried about the performance. Custom tags are DEFINITELY slower than UDFs/CFCs. However, I don't think they are a cause for concern for 95% of you (you being my readers), and like anything, if performance is a concern, you want to be careful about _all_ the code you write.
# Posted By Raymond Camden | 8/17/06 2:59 PM
So if you're already taking the performance hit for Custom tags in the first place, you might as well go whole hog, and use less ambigous code.

That makes sense to me. Thanks.
# Posted By Terrence Ryan | 8/17/06 3:04 PM
Less amigous? Sorry - can you restate that.
# Posted By Raymond Camden | 8/17/06 3:08 PM
I meant of course "ambiguous."

Being ambiguous on the other hand, was unintented.
# Posted By Terrence Ryan | 8/17/06 3:12 PM
I believe Sean argues for cf_ or cfimport syntax over cfmodule.

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.
# Posted By Steve Bryant | 8/17/06 3:13 PM
I have some issues with the whole return variable for custom tags... my feeling is that if it has a return variables, but not just make it UDF, that way you can explicitly use or not use the return value. In my head (which has issues of its own), custom tags are more for page output and the idea of a return variable seems a bit odd. I can understand it for backwards compatibility, but going forward in all the MX stuff and the OOP and the frameworks, does it really make sense to have custom tags that have return variables?

(ps. I am not attacking, I am geninuingly interested in this idea)
# Posted By Ben Nadel | 8/17/06 3:14 PM
Steve: My concern is that I may not know if the app will go to a single server or a hosted server. THerefore, I never trust cf_ syntax.

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.
# Posted By Raymond Camden | 8/17/06 3:22 PM
Ben,

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).
# Posted By Steve Bryant | 8/17/06 3:28 PM
Are you sure that when someone calls CFC's in the taggy way of not actually creating an object and accessing it that custom tags are slower? I was thinking they were only faster, but not sure, when you actually create an instance and use the methods rather than <cfinvoke...> the CFC like it was a custom tag. (Please, guys who like CF Invoke... don't get heated... just trying to get a techincal answer, not start a flame war.)
# Posted By John Farrar | 8/17/06 3:32 PM
I happen to love CFImport. I love that you can use good directory paths and it makes grouping tags sooo freakin' nice. For instance, I have a bunch of FORM tags that all have the prefix FORM:

<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.
# Posted By Ben Nadel | 8/17/06 3:32 PM
Steve, what do you mean by flexibility? Whether you use cfimport, cf_, or cfmodule, you have the exact same features.
# Posted By Raymond Camden | 8/17/06 3:32 PM
Sorry I was clear. I meant that cfmodule and cfimport are both are more flexible than cf_ inasmuch as I can specify the exact location of the file I want to use.

With cf_, ColdFusion has a set pattern it follows to find the file. I can't direct it to look where I want.
# Posted By Steve Bryant | 8/17/06 3:37 PM
John, I'm not sure I read you right. CFINVOKE isn't slower if you use an instance. Ie

<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.
# Posted By Raymond Camden | 8/17/06 3:38 PM
I still like custom tags also... in fact we are working on some custom tags with spry. To me there is "more" power for nested attributes of nested tags in custom tags than there is with CFCs. It's not a case either one being the overall best... but rather which one is best for the task at hand. I like and use them both!
# Posted By John Farrar | 8/17/06 3:39 PM
Guess we are posting back to back Ray! LOL

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!
# Posted By John Farrar | 8/17/06 3:41 PM
Steve: Gotcha.

John: Cool. You love Spry too, right?

I agree - nested tagd are very powerful if used correctly.
# Posted By Raymond Camden | 8/17/06 3:41 PM
OK... how do we make the gravitars work Ray?
# Posted By John Farrar | 8/17/06 3:42 PM
You have to register at gravatar.com. GOod luck. It took me 2 months.
# Posted By Raymond Camden | 8/17/06 4:26 PM
It wasn't quite two months ago that I registered at Gravatar. I got the email saying mine was rated G, obviously, if you can actually see it here. Cool idea. (Looking forward to the day we can all pick which comments to skip by glancing at the icons next to them...j/k)
Alan
# Posted By Alan | 8/18/06 9:34 AM
Ahh, yes.. good posting Ray, I had forgotten about those pesky custom tags (after doing lots of spectra, I am glad to be away from them!) but yes, it reminded me that I need to add some functionality to <cfmodule to give you the attributes of the custom tag that you have defined.

I shall look into this as a future feature

MD
# Posted By Mark Drew | 8/18/06 12:12 PM
Ray,

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
# Posted By Nick | 8/19/06 10:56 AM
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).
# Posted By Steve Bryant | 8/19/06 1:25 PM
Hi Steve,

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
# Posted By Nick | 8/19/06 2:28 PM
Ray... if you use cfimport and reference the root directory of your site as your base it works great! (You can of course also put an application.cfm in the directory with your custom tags to keep malicious security hazards away.) What you get is a directory like "shared" off the root that houses your custom tags in a nested directory.

/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.
# Posted By John Farrar | 8/19/06 3:29 PM
I still don't like cfimport. Period. :)
# Posted By Raymond Camden | 8/19/06 7:22 PM
I concur with Steve. You shouldn't break encapsulation when it comes to custom tags... but I've done it myself every now and then. For example with DSNs.
# Posted By Raymond Camden | 8/19/06 7:25 PM
Finally you are posting about custom tags! Today is my lucky day then because I've been meaning to ask you this question for awhile now Ray but first you should be punished for not using cfimport. ;) I find CJ's CF Best Practices on easycfm as a great set to follow. One that I'm very vocal about is to always scope your variables. Is it necessary to scope your variables in custom tags?? By variables I mean regular variables that should only exist in that custom tag, meaning should I just do:

<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!
# Posted By Javier Julio | 8/21/06 2:15 PM
I would say no, you do not need to variable scope your variables inside a custom tag.

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.
# Posted By Raymond Camden | 8/21/06 3:08 PM
Thats a brilliant idea Ray as I don't dig a lot of the commercial stuff on the MMExchange so it would be great to see cflib support custom tags as well. If you need contributions I will have several for you. One of them being by own version of your data table and column tags. With the neat getMetaData() function thinking about using it to determine column datatypes so you don't have to specify it.
# Posted By Javier Julio | 8/21/06 3:13 PM
What's up with using CFPARAM within a custom tag?

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!
# Posted By Carry | 9/25/06 1:42 PM
I haven't done speed tests on cfparam versus a cfif block. To be honest I don't think most (not all!) speed tests are really worth your time.

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.
# Posted By Raymond Camden | 9/25/06 1:45 PM
Wow! Expert advice in real time!

I always confuse myself when I read too much.

Thank you :^)
# Posted By Carry | 9/25/06 1:51 PM
Remember that my opinion may not be shared by others - especially the "don't worry about speed" comment (which, to be clear, I'm saying to not worry at a very low level). Anyway - just warning you that you may see a bunch of folks chiming in to say I'm wrong. ;)
# Posted By Raymond Camden | 9/25/06 1:56 PM
Hi,

Could any body confirm whether using <cfmodule> will physically include the whole file in to the parent file.

Thanks
# Posted By praman | 10/3/06 1:45 AM
"Include" is the wrong word. The entire file is used - but it isn't "included" as the code has it's own variable space. Therefore it is NOT the same as a cfinclude call.
# Posted By Raymond Camden | 10/8/06 9:35 AM
In general CFC's are actually not faster than custom tags, they are slower.
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.
# Posted By Russ Michaels | 11/1/07 6:22 PM
I'm not so sure that is true in CF8, where CFC creation was improved dramatically.

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.
# Posted By Raymond Camden | 11/1/07 7:50 PM
Yes I have heard that about CF8 too, but I have not yet tested it. I would hope it is true because it would certainly make things a lot easier on our hosting servers which are full of badly written code :-)
# Posted By Russ Michaels | 11/1/07 8:20 PM
at first i didn't really like using cfimport, but it was the only clean option available
# Posted By Arowolo M.A | 4/19/08 7:47 PM