views:

164

answers:

3

I'm creating a set of ColdFusion custom tags designed to make reusing certain layout elements easy. I'll be using them in a manner similar to the following:

<cfimport prefix="layout" taglib="commonfunctions/layouttags">

<layout:fadingbox>
    This text will fade in and out
</layout:fadingbox>
<layout:stockticker>
    This text will scroll across the screen
</layout>

In order for the code these custom tags generates to work, a javascript file needs to be linked into the page like so:

<script src="commonfunctions/layouttags/enablingscript.js" type="text/javascript"></script>

I'd prefer to include the script from inside the custom tags, instead of making the user include it himself. The issue is that the javascript file should only be included once per page. After the first time one of these custom tags is used, I'd like subsequent calls to the same tag on the same page to avoid repeating the <script> tag. It's occured to me that I could do something like this...

<cfif NOT isDefined("Caller.LayoutTagInitialized")>
    <script src="commonfunctions/layouttags/enablingscript.js" type="text/javascript"></script>
</cfif>
<cfset Caller.LayoutTagInitialized = 1>

...But it seems inelegant. I wonder, is there a better way? How would you implement this?

Edit - Clarification:

In case what I wrote above didn't make sense, here's a more detailed example:

If I have a custom tag like this...

<cfif ThisTag.ExecutionMode EQ "start">
    <script src="commonfunctions/layouttags/enablingscript.js" type="text/javascript"></script>
    <div class="mytag">
<cfelse>
    </div>
</cfif>

...and I have CFML markup calling the tag like like this...

<layout:mytag>
    One
</layout:mytag>
<layout:mytag>
    Two
</layout:mytag>
<layout:mytag>
    Three
</layout:mytag>

...I want HTML like the following to be generated:

<!-- Script included only the first time the tag is called -->
<script src="commonfunctions/layouttags/enablingscript.js" type="text/javascript"></script>
<div class="mytag">
    One
</div>
<!-- No <script> tag on the second call -->
<div class="mytag">
    Two
</div>
<!-- No <script> tag on the third call -->
<div class="mytag">
    Three
</div>
A: 

Custom tags have a built in scope called thistag.

This code will work:

<cfif thisTag.ExecutionMode eq "start">
Sam Farmer
I know about that. That's not what I'm referring to. This is what I want: <layout:fadingbox>Script tag incl here,</layout:fadingbox><layout:fadingbox>But not here</layout:fadingbox><layout:fadingbox>And also not here.</layout:fadingbox>. See?
Joshua Carmody
Question edited to clarify.
Joshua Carmody
ah, i see what you mean. I don't think there's anything wrong with how you implemented it. I would probably use the request scope instead of the caller scope but thats more preference than anything.
Sam Farmer
+1 for request scope. And I would name the variable something like __include_[sanitized_file_name].
Adam Tuttle
There we go: I added a "Request Scope" answer, so people can *actually* vote for it. :)
Peter Boughton
Also, I would use something like Request.CustomTagData.Layout.FadingBox rather than doing that ugly underscore stuff.
Peter Boughton
+6  A: 

Use the Request scope.

Peter Boughton
Ok, I guess the way I was doing it was as good as it gets, although it makes sense to use Request instead of Caller. I was hoping for a <cfloadonlyonce> or something, I guess.
Joshua Carmody
+1  A: 

Your solution isn't far off.

Sam's right that the executionmode is what you want to use when you're wanting something to come out in the start or end mode of the tag, which is part of what you want.

But then you say you want that script tag put out in the start mode of only the first tag used on the page.

That's where you would use Peter's suggestion of the request scope. Unlike the default (or "variables") scope, the request scope is shared among all custom tags on a given request. You proposed using the caller scope, and that could work, too, unless the caller was another custom tag, in which case the caller scope would only be the local scope in the custom tag. The request scope (which has been around since about CF 4.01) is your best choice.

In that case, your proposed solution was close: in the custom tag, in the start mode, programatically check if you have already created a tracking variable in the request scope when you put the script tag out the first time. If not, put out the script tag and create the tracking variable.

Other than changing your code from using caller to request, I'd also suggest you'd want to put the CFSET inside the IF. No need to execute it again for when the IF test fails.

charlie arehart