Ask a Jedi: CFASSOCIATE Example

This post is more than 2 years old.

Kaushal asks:

Can you give an example and explanation ofplease?

Certainly! The cfassociate tag is used to pass data between child custom tags and the parents above them. To be precise, the cfassociate tag allows you to pass attribute data from a child to a parent. That distinction may not make sense at first, so let's look at a simple example.

First, our template:

<cf_parent name="ray">
&lt;cf_child name="jacob"&gt;
&lt;cf_child name="lynn"&gt;
&lt;cf_child name="noah"&gt;

</cf_parent>

The code calls a custom tag called parent. Inside of this call are 3 calls to a custom tag named child. Within parent.cfm I'll just dump out the thisScope, but only in the End execution mode:

<cfif thisTag.executionMode is "end"> <cfdump var="#thisTag#" label="thisTag"> </cfif>

Assuming child.cfm is just an empty file, our dump will be:

Nothing unusual here. So here is where cfassociate comes in. What if we wanted the parent tag to be able to introspect data from the kids? We can simply add a cfassociate tag like to create this connection. Here is child.cfm:

<cfassociate basetag="cf_parent">

The cfassociate tag has only one required attribute, the name of the tag to share data with. Notice the cf_ in front. Even though, mentally, I'd "name" the tag parent, ColdFusion uses a cf_ in front to signify that it is a custom tag. Now when we run the tag we see something interesting:

The thisTag structure has a new key, AssocAttribs, and an array of structures. Notice that the structure data matches what we passed to the child. This is an important point. The only data passed from the child to the parent are items in the child's Attributes scope. They need not be attributes passed in either. If child.cfm does:

<cfset attributes.x = 1>

Then this data will be passed back as well. So where did the name AssocAttribs come from? This is the default location where ColdFusion will pass back child data. So you might ask - what if I have something really complex going on? Maybe something like:

<cf_parent name="ray">
&lt;cf_child name="jacob"&gt;
&lt;cf_child name="lynn"&gt;
&lt;cf_child name="noah"&gt;

&lt;cf_pet type="dog" name="phyliss"&gt;
&lt;cf_pet type="dog" name="ginger"&gt;
&lt;cf_pet type="cat" name="hoshi"&gt;
&lt;cf_pet type="cat" name="that gray one"&gt;
&lt;cf_pet type="cat" name="that orange fat one"&gt;

</cf_parent>

If pet.cfm uses the same cfassociate tag, we end up with this:

A bit confusing, isn't it? Luckily cfassociate allows us to specify another location for our data. By using the "datacollection" argument we can specify another structure key for the data. So I've modified child.cfm like so:

<cfassociate basetag="cf_parent" datacollection="childdata">

and pet.cfm like so:

<cfassociate basetag="cf_parent" datacollection="petdata">

Now the data is segregated and easier to deal with:

Sweet. As for what you do with that data... well it's up to you. In my 10+ years of writing CFML applications I've used this feature only once or twice. Just to complete the example though I've modified parent.cfm to inspect the child data.

<cfif thisTag.executionMode is "end">

&lt;cfif structKeyExists(thisTag, "childdata")&gt;
	&lt;cfoutput&gt;
	I have #arrayLen(thisTag.childdata)# children. Their names are:&lt;br/&gt;
		&lt;cfloop index="x" from="1" to="#arrayLen(thisTag.childdata)#"&gt;
			#thisTag.childdata[x].name#&lt;cfif x lt arrayLen(thisTag.childdata)&gt;, &lt;/cfif&gt;
		&lt;/cfloop&gt;
	&lt;/cfoutput&gt;
	&lt;p/&gt;
&lt;/cfif&gt;

&lt;cfif structKeyExists(thisTag, "petdata")&gt;
	&lt;cfoutput&gt;
	I have #arrayLen(thisTag.petdata)# pet(s). Their names are:&lt;br/&gt;
		&lt;cfloop index="x" from="1" to="#arrayLen(thisTag.petdata)#"&gt;
			#thisTag.petdata[x].name# (#thisTag.petdata[x].type#)&lt;cfif x lt arrayLen(thisTag.petdata)&gt;, &lt;/cfif&gt;
		&lt;/cfloop&gt;
	&lt;/cfoutput&gt;
	&lt;/p&gt;
&lt;/cfif&gt;

</cfif>

I've simply checked to see if any child or pet custom tag was run, and if so, I inspect the array of data for each. To be more complete I should ensure that name and type exist in the relevant structures, but you could imagine that being done at the child/pet level instead.

Anyway, I hope this helps.

p.s. An off topic tip not necessarily related to the main question. You may ask - why didn't you close the child tags? Ie <cf_child name="jacob"/>. I normally would. To ensure that a tag doesn't run twice (once in "end" mode) when you don't really want it to, just add a <cfexit mode="exitTag"> to the end of that tag.

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 brian posted on 10/9/2009 at 11:54 PM

juat add a / ?

Comment 2 by Raymond Camden posted on 10/9/2009 at 11:56 PM

I assume you are referring to the typo at the end? If so - fixed.

Comment 3 by todd sharp posted on 10/10/2009 at 12:18 AM

cfassociate is a pretty handy little tag IMO. I remember using it in my cftimeline project - it has some good examples of parent/child custom tag action if anyone wants to check it (via riaforge). not necessarilly my best code but hey it was a few years ago and my first 'deep-dive' into custom tags.

getBaseTagList() is another helpful function when working with custom tags. It let's you do things like so:

<cfset baseTags = getBaseTagList()>

<cfif not listFindNoCase(baseTags,"cf_timeline")>
<cfthrow type="cf_timelineevent" message="The cf_timelineevent tag must be nested within a cf_timeline.">
</cfif>

Comment 4 by Kaushal Shah posted on 10/10/2009 at 11:25 AM

thanks for ur example.
i now understood how the cfassociate works now.

Comment 5 by ColbyA posted on 10/20/2009 at 12:10 AM

"just add a to the end of that tag"

The <cfexit mode="exitTag"> isn't showing up in the post. I can see it in the source but the less than and greater than aren't entity escaped.

Comment 6 by Raymond Camden posted on 10/20/2009 at 12:13 AM

Fixed, thanks ColbyA.