This post is more than 2 years old.
Can you give an example and explanation of
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_child name="jacob"> <cf_child name="lynn"> <cf_child name="noah">
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:
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_child name="jacob"> <cf_child name="lynn"> <cf_child name="noah"> <cf_pet type="dog" name="phyliss"> <cf_pet type="dog" name="ginger"> <cf_pet type="cat" name="hoshi"> <cf_pet type="cat" name="that gray one"> <cf_pet type="cat" name="that orange fat one">
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">
<cfif structKeyExists(thisTag, "childdata")> <cfoutput> I have #arrayLen(thisTag.childdata)# children. Their names are:<br/> <cfloop index="x" from="1" to="#arrayLen(thisTag.childdata)#"> #thisTag.childdata[x].name#<cfif x lt arrayLen(thisTag.childdata)>, </cfif> </cfloop> </cfoutput> <p/> </cfif> <cfif structKeyExists(thisTag, "petdata")> <cfoutput> I have #arrayLen(thisTag.petdata)# pet(s). Their names are:<br/> <cfloop index="x" from="1" to="#arrayLen(thisTag.petdata)#"> #thisTag.petdata[x].name# (#thisTag.petdata[x].type#)<cfif x lt arrayLen(thisTag.petdata)>, </cfif> </cfloop> </cfoutput> </p> </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.