Did You Know: Looping with ColdFusion Custom Tags

This post is more than 2 years old.

A user on the CF irc channel had an interesting problem. She was trying to use a custom tag to iterate over some data. What most folks don't realize is that custom tags can act as iterators, looping over their body as many times as you want. Consider this first code sample:

<cf_looper from="1" to="10" index="x">
&lt;cfoutput&gt;#x#&lt;/cfoutput&gt;&lt;br&gt;

</cf_looper>

Now, obviously, you wouldn't do this. You would just use the loop tag. But what if you did? Let's take a look at how looper.cfm would work:

<cfparam name="attributes.from" type="numeric"> <cfparam name="attributes.to" type="numeric"> <cfparam name="attributes.index" type="variableName">

<cfif not isDefined("counter")> <cfset counter = attributes.from> </cfif>

<cfif thisTag.executionMode is "start">

&lt;cfset caller[attributes.index] = counter&gt;

<cfelse>

&lt;cfset counter = counter + 1&gt;
&lt;cfset caller[attributes.index] = counter&gt;

&lt;cfif counter lte attributes.to&gt;
	&lt;cfexit method="loop"&gt;
&lt;/cfif&gt;

</cfif>

The first three lines simply validate my arguments. We then create a variable to serve as our counter. We start it at our FROM value. We then branch between the start and end execution of our custom tag. When ColdFusion sees <cf_looper>, it runs the tag with thisTag.executionMode equal to start. When ColdFusion sees </cf_looper>, executionMode is end. Now pay attention to what I do in there. First I increase counter. I copy the value again. (This is so that my calling document can output the value.) Then I check to see if I'm at the end of my loop. If I'm not, I use cfexit with method="loop". What that tells ColdFusion is - return to right after <cf_foo>, basically the inside of my tag, execute the code there, than run <cf_foo> in end mode again.

To be honest, I haven't seen many people use the tag like this. The last time I saw it in production mode was in Spectra. Spectra would wrap a content handler with a tag so it could be executed N times. You can imagine code that would print the "Teaser" for an article. You would write the display (Name, a line break, and a portion of the body), wrap it in the tag, and it would work correctly for one content object, or twenty. You could even tell it to use a hr tag, or some other html tag, between each item. Handy! (Not that many of my readers even remember Spectra. -sigh-)

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Seth Petry-Johnson posted on 12/24/2005 at 7:10 PM

FWIW I remember Spectra. Well, at least I remember READING ABOUT Spectra in CFDJ. Never did get a chance to use it :(

Merry Christmas!

Comment 2 by Jeff posted on 12/24/2005 at 8:24 PM

Nowhere in your code do you have a "cf_foo" which may make your explanation of the code confusing to some (like me)

Where exactly does CF return to after hitting the exit? I think you meant "cf_looper" in your desciprion text.

Comment 3 by Raymond Camden posted on 12/24/2005 at 9:12 PM

Ah yes, where I say cf_foo, I meant cf_looper. So right, when the cfexit is run, we go back to the "middle" portion, the stuff after the starting cf_looper tag. Basically we rerun the middle and the end again.

Comment 4 by Patrick McElhaney posted on 12/27/2005 at 5:46 PM

Thanks for the reminder.

I haven't thought about custom tags much since I started using CFCs, but this could come in handy. For example, we could make a cf_foreach tag to loop over the elements in a Java collection.

Comment 5 by Adam Cameron posted on 8/14/2010 at 4:59 PM

Ray, you are a star.

I've been confronted with a requirement to do a "repeater" sort of construct with a custom tag which before I started looking at it I thought "yeah, how hard can that be? All one needs to do is... is... [voice trails off]... umm...", then - despite having been doing CF for about ten years now - I realised I had never had to do this before and had no idea how to get it to work. And the CF docs were no bl**dy use whatsoever.

My initial approach of bashing my head against the wall and swearing at my code a lot didn't work too well, but then with the assistance of Google & your blog, I've got it working.

Thanks mate. That's yet another beer I owe you.

--
Adam

Comment 6 by Raymond Camden posted on 8/14/2010 at 5:15 PM

You're lucky I'm a light weight - 3 beers in and you can tell me we are caught up. ;)

Comment 7 by Adam Cameron posted on 8/14/2010 at 6:17 PM

I seem to recall you had a few more than three last time we sat down. Well *I* certainly had a few more than three... and you seemed to be keeping up... ;-)

--
Adam

Comment 8 by Raymond Camden posted on 8/14/2010 at 6:18 PM

Heh, true - I've had "practice" for a few years. :)