Cold Fusion Custom Tags How To Block generatedContent if executionMode eq start

49 views Asked by At

I'm trying to figure out how to use coldfusion custom tags but can't figure out why the html/text nested inside the custom tag renders twice.

TLDR

I'm simply trying to make a custom tag that can accepts two attributes and uses them in the output as well as integrating any html/text nested inside the custom tag

Example

<!--- root.cfm --->

    <cf_sameDirTag id="Tag 1" class="Oranges">
       <div>My Inner Content</div>
    </cf_sameDirTag>

<!--- sameDirTag.cfm (this file is in same directory as root file) --->

<cfparam name="attributes.id" type="string" default="">
<cfparam name="attributes.class" type="string" default="">

<cfif thisTag.executionMode eq "start">
    <!--- NOTE Start tag processing  --->
    <br>
    <div>Start</div>
    <cfoutput>
        <div class="flex flex-col gap-2">
            <div>ID: #attributes.id#</div>
            <div>Class: #attributes.class#</div>
        </div>
    </cfoutput>
<cfelse>
    <!--- NOTE End tag processing  --->
    <br>
    <div>End</div>
    <cfoutput>
        <div class="flex flex-col gap-2">
            <div>ID: #attributes.id#</div>
            <div class="flex flex-row gap-2">GenContent: #thisTag.generatedContent#</div>
            <div>Class: #attributes.class#</div>
        </div>
    </cfoutput>
</cfif>

It seems cold fusion custom tags process twice if they have an open and closing tag. This can result in the tag being run twice. So to get around this you need to add the thisTag.executionMode check as i've done. In this example I'm printing mostly the same content for both start and end tag for demonstrative purposes, but ideally I would comment out the code when execution mode = "start" so that way we only process once during the end tag which gives us access to thisTag.generatedContent which we can freely insert wherever we want in our code.

The problem

I'm running into is no matter what the content nested inside my custom tag seems to render just after the opening tag of my custom tag ends. This semi makes sense because in the code <div>My Inner Content</div> does appear just after the opening tag.

    <cf_sameDirTag id="Tag 1" class="Oranges">
       <div>My Inner Content</div>
    </cf_sameDirTag>

However, it also makes no sense because what is the point of being able to use thisTag.generatedContent in the end tag if that content is going to be pasted once beforehand anyway without control to choose where it's output?

This is what my current code outputs, if I commented out all code when thisTag.executionMode="start" the part labeled "bad" would still appear which is my core issue.

enter image description here

1

There are 1 answers

0
Adam Cameron On

It might be worth reading the docs: Executing custom tags. It explains it reasonably clearly, and it makes sense.

Here is a very cut down example to make it clearer:

<!--- tag.cfm --->
<cfif thisTag.executionMode EQ "start">
    Start processed<br>
    <cfexit method="exittemplate">
</cfif>
<cfset processedContent = "PROCESSED: [#thistag.generatedContent.trim()#]">
<cfset thisTag.generatedContent = "">
End processed with <cfoutput>#processedContent#</cfoutput><br>

<!--- test.cfm --->
<cfimport prefix="ct" taglib=".">
<ct:tag>
    content
</ct:tag>

Notes:

  • Normally one would not put output in the start section. That's just for attribute value preparation, and other bootstrapping logic. Here I output something just for the sake of showing that it did something.
  • All the heavy lifting goes in the end tag process, cos that's when the tag code knows what got run between the tags.
  • Any output generated between the tags is captured in thisTag.generatedContent. On the whole one might want to grab that for further processing, but then clear it, replacing it with the actual output you want to emit. I think this is the bit yer not quite understanding.
  • One can either clear the thisTag.generatedContent value and then just emit different text (as per my example), or just change the thisTag.generatedContent value, eg I could have done this:
<cfset thisTag.generatedContent = "End processed with: [#thistag.generatedContent.trim()#]">

In this case the CF engine will emit that thisTag.generatedContent value when the tag completes. It depends what yer doing as what the best approach is here.