Ask Ben: Executing ColdFusion Custom Tag Code If First Run Only

Someone asked me earlier about executing part of a ColdFusion custom tag only if it was the first instance of the tag run of the given page. Basically, what they were trying to do was create reusable UI widgets that had associated Javascript. The given UI widget tags could be used any number of times on the page, but they only wanted the Javascript portion to render once, in the first custom tag execution as it would initialize each UI widget on page load.

To do this, each instance of the custom tag would have to be, to some extent, aware of each of its siblings. Since each tag executes inside of its own bubble, I have to keep ColdFusion custom tag meta data in one of the page scopes to and from which each custom tag can write and read respectively. Traditionally, I use the REQUEST scope as this is both globally available and persistent for a single page request. To avoid naming collisions, I like to create a name space within the REQUEST scope that is specific to custom tags in general and to this tag specifically.

By paraming this ColdFusion custom tag "name space" in the tag ATTRIBUTES scope, it allows each tag to have a default name space with the ability to be overridden by the calling context. Because this name space is dynamic, you would think it would be complicated to work with; but, due to the behavior of the CALLER scope and the auto-struct-path creation behavior of ColdFusion, it's actually quite easy!

To demonstrate this, I have some test code below that executes a demo ColdFusion custom tag three times. Each of the custom tags has its own HTML output plus some Javascript output. The Javascript output, as per the readers question, will only be output once during the first execution of the custom tag:

<!--- Run the custom tag. --->

<cf_demo />

<!--- Run the custom tag. --->

<cf_demo />

<!--- Run the custom tag. --->

<cf_demo />

When we run this code, we get the following PAGE SOURCE output (I've stripped some white space for readability):

<script type="text/javascript">// Script would go here.</script>

Tag 1<br />Tag 2<br />Tag 3<br />

As you can see, the SCRIPT tag has only been rendered once during the first custom tag execution, but the HTML output has been rendered once for each tag.

So, how does this work? Here is the ColdFusion custom tag that was executed:

Demo.cfm

<!--- Turn on explicit output. --->

<cfsetting enablecfoutputonly="true" />

<!---

Param the tag attribute for our name space. To make sure

that the meta data that we store with this tag does not

conflict with other page variables, we will create namespace

for storage. This name space can be overridden by the

calling code.

--->

<cfparam

name="ATTRIBUTES.NameSpace"

type="variablename"

default="REQUEST.CustomTagNameSpaces.Demo"

/>

<!---

Check to see if the namespace for this tag exists yet.

If not, we will create a default version.

--->

<cfif NOT StructKeyExists( CALLER, ATTRIBUTES.NameSpace )>

<!--- Create default name space for this tag. --->

<cfset CALLER[ ATTRIBUTES.NameSpace ] = {

JavaScriptRendered = false,

TagCount = 0

} />

</cfif>

<!---

ASSERT: At this point, we can access the name space for

this tag (even if it was just created).

--->

<!--- Check to see if the Javascript has been rendered. --->

<cfif NOT CALLER[ ATTRIBUTES.NameSpace ].JavaScriptRendered>

<!--- Render Javascript. --->

<cfoutput>

<script type="text/javascript">

// Script would go here.

</script>

</cfoutput>

<!--- Flag script as being rendered. --->

<cfset CALLER[ ATTRIBUTES.NameSpace ].JavaScriptRendered = true />

</cfif>

<!---

ASSERT: At this point, we know that the Javascript has

either been rendered by this tag or a previous tag.

--->

<!--- Render tag content. --->

<cfoutput>

Tag #++CALLER[ ATTRIBUTES.NameSpace ].TagCount#<br />

</cfoutput>

<!--- Turn off explicit output. --->

<cfsetting enablecfoutputonly="false" />

<!--- Exit tag. --->

<cfexit method="exittag" />

As you can see, I am paraming a name space value in the custom tag ATTRIBUTES scope:

REQUEST.CustomTagNameSpaces.Demo

This value has to be a valid "variable name" data type otherwise we won't be able to leverage the awesome power of the ColdFusion CALLER scope. Like I said before, I like to use a REQUEST-based struct; but, because this variable name is defaulted in the ATTRIBUTES scope, the calling context could easily override it:

<cf_demo name space="VARIABLES.TagData" />

Notice that once we have the name space variable, I make no explicit references to the path, only to the variable which contains it. With this variable, we can check to see if the name space exists using StructKeyExists():

I find that this approach gives us the most usability but provides great flexibility while at the same time, avoiding any naming conflicts that might arise. Every time I use the CALLER scope, I simply love the way that ColdFusion has chosen to implement it - it just makes life so darned elegant.

Reader Comments

I do a similar thing in ColdExt to keep track of loaded JS resources, though I just use the request scope directly, as you say you would traditionally do. Is the combination of the caller scope + StructKeyExists() letting you do something that wouldn't normally be possible, or is it just letting you reference your variables in a shorter (but perhaps more confusing) manner? I think you could still use the request scope directly and have just as much flexibility, e.g:

I had a couple of reactions to this scenario and wanted to share.. They're not a knock on your nifty solution though.

1. The single-execution logic could be placed in the JavaScript side; although using a global JS var to accomplish this, it might feel better than having a custom tag sticking its grimy fingers where they don't belong.. ;-D

Then your custom tag just writes the JS every time and doesn't worry about that logic.

2. A bit more "controversial"... But a CFC could handle this task pretty well, and could maintain the state between each execution. This using CFCs for display is obviously blasphemous from the perspective of CFCs in the "model", but the flexibility of CFCs can come in handy here for a very specific "view" purpose.

The idea behind the CALLER scope is that you don't have to use the REQUEST scope at all. The CALLER scope allows you to reach into the calling context and use whatever variable string was passed in (or defaulted) in the attributes. As such, you could override with a VARIABLES-scopes key as I demonstrate part way in the blog.

Think about something like CFThread; perhaps you are using CFThread to burn some HTML to flat files. You probably wouldn't want to use the REQUEST scope in that case because the context of the custom tag (cfthread) might be running in parallel with other threads all doing the same thing. In such a case, you would want them to use their own name-space such as (THREAD.CustomTagData).

Without using the CALLER scope, also, its much harder to reference an unknown variable location. You can set it using dynamic variable naming:

<cfset "#ATTRIBUTES.NameSpace#" = StructNew() />

... of course, if this is a VARIABLES-scoped value, it will incorrectly store it in the custom tag's VARIABLES scope.

But, accessing it is much less elegant; I believe you would have to use an Evaluate() call:

I think maybe the only flexibility you would lose is being able to create the full struct path in a single line of code, as per your caller scope example. Did that end up being a bug that you reported though? Is it something you can rely on, and has it been tested on other CFML engines?

At first, I thought the CALLER scope issue was a bug; but, once I started to see how it could be leveraged, I had to assume that it was designed that way in for those very purposes (especially since a standard struct behavior would make things like that more difficult).

I think you could easily pass in a name-space. You would have to relax the CFParam type to be "any", but then once you had the value, you could test it for string or struct data type:

It didn't, I created my custom tags with the CreateUUID() to be 100% self contained. They each had their own copy of everything they needed to run.

Hence: "Not the most efficient, but it worked..."

For example, if a custom tag needed to call a JS function, the JS Function would look like this.

function popUpWindow#uniqueID#(){ alert('1'); }

Although not the most efficient, I did gain 1 benefit from doing this, when all functions and vars had this unique name to it, I never had to worry about conflicts from any other libraries, or custom JS code...

In other words, I never thought of trying to be aware of other custom tags on a page, and I never even thought of thinking about a solution like you have been discussing. My idea was not a counter idea to what your discussing, simply what I did with my custom tags when I need to have multiple tags on the same page.