Skip to main content
Ben Nadel at Scotch On The Rock (SOTR) 2010 (London) with: Adam Cameron
Ben Nadel at Scotch On The Rock (SOTR) 2010 (London) with: Adam Cameron

Expected And Unexpected getBaseTagData() Behavior In Lucee CFML 5.3.7.47

By
Published in Comments (3)

In the implementation details of my ColdFusion custom tag DSL for HTML emails, I have to access the data exposed by ancestor custom tags. In some cases, the parent tag is dynamic; which means that I have to use the getBaseTagList() function in order to figure out the name of the ColdFusion custom tag that I need to access. It turns out that some native ColdFusion tags show up in the getBaseTagList() value; but, they do not expose any "data". As such, they have to be explicitly skipped-over. Things get even more complicated when you use CFModule to invoke a custom tag. And, since I stumbled over this in my journey, I figured it might be worth a quick demo in Lucee CFML 5.3.7.47.

One way in which a ColdFusion custom tag can communicate with another ColdFusion custom tag is by using the getBaseTagData(). This allows one tag to reach up into the variables scope of another tag to read-from or write-to various data structures. But, calling getBaseTagData() doesn't always work, depending on the type of tag and the way in which the tag was invoked.

To see this in action, I have a test page that nests some native ColdFusion tags and some custom tags. Notice that one custom tag in particular - Wrapper.cfm - is in there twice: once using the CF_ notation and once using CFModule:

<cfsavecontent variable="content">
	<cf_Wrapper>
		<cftimer type="outline">
			<cfmodule template="Wrapper.cfm">
				
				<cf_MyTag />

			</cfmodule>
		</cftimer>
	</cf_Wrapper>
</cfsavecontent>

<cfset echo( content ) />

The cf_MyTag tag is our ColdFusion custom tag that is going to try and walk up the tree of tags and access the data attribute. Each tag will be accessed in a try/catch so that we can see which worked and which didn't:

<cfscript>

	dump( label = "Base Tag List", var = getBaseTagList() );

	// Loop over each item in the base-tag list and try to access the "Data".
	// --
	// CAUTION: This does NOT WORK. Native ColdFusion tags show up in this list but they
	// DO NOT expose tag data the way that custom tags do.
	loop
		item = "parentTagName"
		list = getBaseTagList()
		{

		echo( "<br />" );

		try {

			dump( label = parentTagName, var = getBaseTagData( parentTagName ) );

		} catch ( any error ) {

			dump( "Oh Noes! getBaseTagData( #parentTagName# ) failed!" );

		}

	}

	exit method = "exitTag";

</cfscript>

As you can see, there's nothing special going on here - we're just walking the list of ancestor tags and trying to access the data. And, when we run this ColdFusion code in Lucee CFML, we get the following output:

An attempt to access ColdFusion custom tag base data in Lucee CFML.

Ok, so the first take-away here is that some native ColdFusion tags show up in the getBaseTagList(). If I had to guess, I'd say that it's any tag that is concerned with "wrapping content". For example, while I didn't test it, I would guess that the CFXML tag also shows up in this list since it wraps and parses content.

These native ColdFusion tags should be skipped when dynamically accessing a parent custom tag. In fact, I assume that the only tags that can be accessed are those with the CF_ prefix. Which brings us to the second and arguably much more important lesson: ColdFusion custom tags do not expose data when invoked using CFModule (in Lucee CFML).

If you refer back to test.cfm above, you'll see that the Wrapper.cfm template is in the demo twice:

  • <cf_Wrapper>
  • <cfmodule template="Wrapper.cfm">

And, while this is the same exact tag, getBaseTagData() only works when the tag was invoked using the CF_ prefix, not when using the CFModule tag. This may be related to an earlier issue I posted in which I demonstrated that getBaseTagList() and the CFModule tag works different in Adobe ColdFusion vs. Lucee CFML.

ASIDE: ColdFusion custom tags will also expose data when invoked using the CFImport tag. This is the basis of how my ColdFusion custom tag DSL for HTML emails works - it's CFImport tags all the way down!

Now, if we run similar code in Adobe ColdFusion 2018 (the syntax had to be modified), we get the following output:

An attempt to access ColdFusion custom tag base data in Adobe ColdFusion.

As you can see, with Adobe ColdFusion 2018, the Wrapper.cfm exposes data regardless of the way in which it was invoked (CF_ prefix of CFModule tag). However, when we look at the output of the getBaseTagList(), we see a potentially key difference:

  • Lucee CFML: CF_MYTAG, CFMODULE, CFTIMER, CF_WRAPPER, CFSAVECONTENT

  • ACF 2018: CFDUMP, CF_MYTAGACF, CF_WRAPPER, CFTIMER, CF_WRAPPER, CFSAVECONTENT

In Adobe ColdFusion, the Wrapper.cfm template shows up as CF_WRAPPER regardless of the invocation approach. This speaks to my earlier post about the difference in engines; and, it may be the underlying root cause of the problem. Perhaps Lucee CFML won't even check for base-tag data unless the invocation "expression" starts with CF_?

I'll add this finding as an additional note in the compatibility bug that I filed on the Lucee JIRA server.

Want to use code from this post? Check out the license.

Reader Comments

15,841 Comments

@Mauro,

Hmm, good question. I honestly don't remember which part of my email DSL caused this problem. Because, I certainly do use CFModule extensively inside the DSL implementation, in both Lucee and Adobe ColdFusion.

I just took a look at the code, and it seems that I have some places where I call .filter() on the list (array) of tag names and then only include ones that match the given Regular expression:

^cf_

So, it seems that I only include tags that have the "cf_" prefix, which is when the getBaseTagData() call actually works. It's not a great work-around; but, it worked OK in my particular case. It then just becomes a "known limitation" for the DSL I'm using.

2 Comments

Thanks for your prompt response Ben and may I say its a privilege :-)

Is it an official workaround or a hack that you have tried and tested? Also is applying this in terms need consideration regarding case sensitivity?

Kind regards,
Mauro

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel