High-level data exchange

While the ability to create nested custom tags is a tremendous productivity gain, keeping track of complex nested tag hierarchies can become a chore. The cfassociate tag lets the parent know what the children are up to. By adding this tag to a sub tag, you enable communication of its attributes to the base tag.

In addition, there are many cases in which descendant tags are used only as a means for data validation and exchange with an ancestor tag, such as cfhttp/cfhttpparam and cftree/cftreeitem. You can use the cfassociate tag to encapsulate this processing.

The cfassociate tag has the following format:

<cfassociate baseTag="tagName" dataCollection="collectionName">

The baseTag attribute specifies the name of the base tag that gets access to this tag's attributes. The dataCollection attribute specifies the name of the structure in which the base tag stores the sub-tag data. Its default value is AssocAttribs. You only need to specify a dataCollection attribute if the base tag can have more than one type of subtag. It is convenient for keeping separate collections of attributes, one per tag type.

Note: If the custom tag requires an end tag, the code processing the structure referenced by the dataCollection attribute must be part of end-tag code.

When cfassociate is encountered in a sub tag, the sub tag's attributes are automatically saved in the base tag. The attributes are in a structure appended to the end of an array whose name is thisTag.collectionName.

The cfassociate tag performs the following operations:

<!--- Get base tag instance data --->
<cfset data = getBaseTagData(baseTag)>
<!--- Create a string with the attribute collection name --->
<cfset collection_Name = "data.#dataCollection#">
<!--- Create the attribute collection, if necessary --->
<cfif not isDefined(collectionName)>
<cfset #collection_Name# = arrayNew(1)>
</cfif>
<!--- Append the current attributes to the array --->
<cfset temp=arrayAppend(evaluate(collectionName), attributes)>

The code accessing sub-tag attributes in the base tag could look like the following:

<!--- Protect against no sub-tags --->
<cfparam Name='thisTag.assocAttribs' default=#arrayNew(1)#>

<!--- Loop over the attribute sets of all sub tags --->
<cfloop index=i from=1 to=#arrayLen(thisTag.assocAttribs)#>

<!--- Get the attributes structure --->
<cfset subAttribs = thisTag.assocAttribs[i]>
<!--- Perform other operations --->

</cfloop>

Ancestor data access

The ancestor's data is represented by a structure object that contains all the ancestor's data.

The following functions provide access to ancestral data:

Example: ancestor data access

This example creates two custom tags and a simple page that calls each of the custom tags. The first custom tag calls the second. The second tag reports on its status and provides information about its ancestors.

To create the calling page:

  1. Create a ColdFusion page (the calling page) with the following content:
    Call cf_nesttag1 which calls cf_nesttag2<br>
    <cf_nesttag1>
    <hr>
    
    Call cf_nesttag2 directly<br>
    <cf_nesttag2>
    <hr>
    
  2. Save the page as nesttest.cfm.

To create the first custom tag page:

  1. Create a ColdFusion page with the following content:
    <cf_nesttag2>
    
  2. Save the page as nesttag1.cfm.

To create the second custom tag page:

  1. Create a ColdFusion page with the following content:
    <cfif thisTag.executionmode is 'start'>
    	<!--- Get the tag context stack. The list will look something like 
    	"MYTAGNAME, CALLINGTAGNAME, ..." --->
    	<cfset ancestorlist = getbasetaglist()>
    
    	<!--- Output your own name. You are the first entry in the context stack. 
    --->
    	<cfoutput>
    	<p>I'm custom tag #ListGetAt(ancestorlist,1)#</p>
    	
    	<!--- output all the contents of the stack a line at a time --->
    	<cfloop index="loopcount" from="1" to="#listlen(ancestorlist)#">
    	Ancestorlist entry #loopcount# n is 
    #ListGetAt(ancestorlist,loopcount)#<br>
    	</cfloop><br>
    	</cfoutput>
    
    	<!--- Determine whether you are nested inside a custom tag. Skip the first
    element of the ancestor list, i.e., the name of the custom tag I'm in ---> <cfset incustomtag = ''> <cfloop index="elem" list="#listrest(ancestorlist)#" <cfif (left(elem, 3) eq 'cf_')> <cfset incustomtag = elem> <cfbreak> </cfif> </cfloop> <cfif incustomtag neq ''> <!--- Say you are there ---> <cfoutput> I'm running in the context of a custom tag named #inCustomTag#.<p> </cfoutput> <!--- Get the tag instance data ---> <cfset tagdata = getbasetagdata(incustomtag)> <!--- Find out the tag's execution mode ---> I'm located inside the <cfif tagdata.thisTag.executionmode neq 'inactive'> custom tag code either because it is in its start or end execution mode. <cfelse> body of the tag </cfif> <p> <cfelse> <!--- Say you are lonely ---> I'm not nested inside any custom tags. :^( <p> </cfif> </cfif>
  2. Save the page as nesttag2.cfm.
  3. Open the file nesttest.cfm in your browser.


View comments in LiveDocs