Associating Parent/Child Custom Tags (UPDATED!)
Mark Drew posted a question on his blog wondering how you might pass data to a custom tag that acts as a loop. In his post, he's trying to get the following code:
<cms:text value="bob">
<cms:loop from="1" to="10">
<cms:text value="bob">
</cms:loop>
To output the following:
I am 1 bob
I am 2 bob
I am 3 bob
I am 4 bob
I am 5 bob
I am 6 bob
I am 7 bob
I am 8 bob
I am 9 bob
I am 10 bob
The solution is to use the parent custom tag as an iterator, which you can do using the <cfexit method="loop"> which will cause the parent tag to start process at the first child tag it finds. This functionality isn't very well documented, and quite frankly, it's something I just learned was possible today.
Here's some source code that shows this off.
<cfparam name="attributes.to" type="numeric" />
<cfparam name="attributes.step" type="numeric" default="1" />
<cfswitch expression="#thisTag.ExecutionMode#">
<cfcase value="start">
<!---// we're going to start a loop counter to track iterations //--->
<cfset iLoopCounter = attributes.from />
</cfcase>
<cfcase value="end">
<!---// make the next step in the iteration //--->
<cfset iLoopCounter = iLoopCounter + attributes.step />
<!---//
to create a loop, we need to check to see if the current
loop count is less than the number we're to loop to. if it
is, we'll invoke the <cfexit method="loop" /> command to
start process the first child tag.
//--->
<cfif iLoopCounter lte attributes.to>
<!---// start process from the first child tag //--->
<cfexit method="loop" />
</cfif>
</cfcase>
</cfswitch>
<!---// check to see if we were called from within the loop //--->
<cfif listFindNoCase(getBaseTagList(), "cf_loop") gt 0>
<!---//
if inside the loop tag, we need to associate ourselves w/the loop tag.
this will let the loop tag have access to our variables
//--->
<cfassociate baseTag="cf_loop">
<!---// this is a reference to the parent loop tag //--->
<cfset oParent = getBaseTagData("cf_loop")>
<!---// output the value of the current loop and the value of the tag //--->
I am <cfoutput>#oParent.iLoopCounter#</cfoutput> <cfoutput>#attributes.value#</cfoutput>
<br />
<!---// ok, we're a standalone tag, so just output the text //--->
<cfelse>
<cfoutput>#attributes.value#</cfoutput>
<br />
</cfif>
<cms:text value="bob">
<cms:loop from="1" to="10">
<cms:text value="bob">
</cms:loop>
Create all those files in the same directory and run the test.cfm script and you should get the output Drew was hoping to achieve.
