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">
<cfoutput>#x#</cfoutput><br>
</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">
<cfset caller[attributes.index] = counter>
<cfelse>
<cfset counter = counter + 1>
<cfset caller[attributes.index] = counter>
<cfif counter lte attributes.to>
<cfexit method="loop">
</cfif>
</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-)
Archived Comments
FWIW I remember Spectra. Well, at least I remember READING ABOUT Spectra in CFDJ. Never did get a chance to use it :(
Merry Christmas!
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.
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.
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.
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
You're lucky I'm a light weight - 3 beers in and you can tell me we are caught up. ;)
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
Heh, true - I've had "practice" for a few years. :)