Can I call a custom tag in cfscript?
Asked Answered
S

3

9

For example, if I have a custom tag like <cf_AppSwitch action="Check"> my assumption would be something like AppSwitch(action="Check"), but I am not certain CF can resolve that as a custom tag.

The other solution I can think of would be to write a wrapper function and call my custom tag, but that feels redundant.

It seems like I am oversimplifying a much more complex problem, so any insight would be appreciated (even as to why this is not/should not be supported).

Scorcher answered 9/2, 2012 at 17:9 Comment(0)
E
7

Assuming you are using Adobe CF, unfortunately the answer is no. You have to write a wrapper function that is CFML-based. For example:

<cffunction name="myCustomTag">
  <cfset var returnVal = "">
  <cfsavecontent variable="returnVal"><cf_myCustomTag attributeCollection=arguments></cfsavecontent>
  <cfreturn returnVal>
</cffunction>

<cfscript>
 myCustomTag(a="b");
</cfscript>

Now, if you are using Railo, you could use the cfscript equivalent to the <cfmodule> tag:

<cfscript>
    module name="myCustomTag";
</cfscript>
Epigene answered 9/2, 2012 at 18:16 Comment(3)
Thanks Jake, just what I was looking for.Scorcher
Some would argue that tags are good for UI based actions and components are better suited to model/services. Therefore it's rare that one would have a need to do such a thing.Hadik
Valid point @Todd Sharp, I am re-writing an app with FW/1 and am having to deal with a bunch of pre-existing custom tags that are utilized by several other apps... you are right, if given the proper time I would re-write them as components.Scorcher
H
12

Update 2:

Here's an even badder ass (or is it bad asser?) way. Warning: undocumented features below (but still cool):

Assume the custom tag returns a value like so:

<cfif thisTag.executionMode eq "start">
    <cfparam name="attributes.name" default="Dude" />
    <cfparam name="attributes.result" type="variablename" default="result" />
    <cfset caller[attributes.result] = "Hello, " & attributes.name & "!!" />
</cfif>

So the result attribute of the tag expects a variable name that will be set into the caller. Now using the method below we can access that result via cfscript.

<cfscript>

test = createObject("java", "coldfusion.tagext.lang.ModuleTag");
test.setPageContext( getPageContext() );
test.setTemplatePath(expandPath('echo.cfm'));
test.setAttributeCollection({name="Todd Sharp", result="testResult"});
test.doStartTag();
test.doEndTag();
test.releaseTag();

writeDump(testResult);

</cfscript>

Update:

The solution below may cause an undesired side effect. If your custom tag returns a value you will not have access to it since the tag is called from the component the return variable gets put into the variables scope of the component, not the calling template. Of course, if you're returning a value you should probably be using a CFC anyways (as I commented above) so use at your own risk.

How about this approach (modified from Jake's):

CustomTagProxy.cfc:

<cfcomponent>

    <cffunction name="onMissingMethod" output="false">
        <cfargument name="missingMethodName" type="string"/>
        <cfargument name="missingMethodArguments" type="struct"/>

            <cfset var returnVal = "">
            <cfsavecontent variable="returnVal"><cfmodule template="#arguments.missingMethodName#.cfm" attributecollection="#arguments.missingMethodArguments#" /></cfsavecontent>
            <cfreturn returnVal>
    </cffunction>

</cfcomponent>

echo.cfm:

<cfif thisTag.executionMode eq "start">
    <cfparam name="attributes.name" default="Dude" />
    <cfoutput>Hello, #attributes.name#!!</cfoutput>
</cfif>

time.cfm:

<cfif thisTag.executionMode eq "start">
    <cfoutput>It is now #now()#.</cfoutput>
</cfif>

index.cfm:

<cfscript>
proxy = new CustomTagProxy();
echoTest = proxy.echo(name="Todd");
timeTest = proxy.time();

writeOutput(echoTest);
writeOutput("<br />");
writeOutput(timeTest); 
</cfscript>
Hadik answered 9/2, 2012 at 22:13 Comment(2)
coldfusion.tagext.lang.ModuleTag ftwSelfmade
here are a ton of other tags you can do in cfscript using this methodSelfmade
E
7

Assuming you are using Adobe CF, unfortunately the answer is no. You have to write a wrapper function that is CFML-based. For example:

<cffunction name="myCustomTag">
  <cfset var returnVal = "">
  <cfsavecontent variable="returnVal"><cf_myCustomTag attributeCollection=arguments></cfsavecontent>
  <cfreturn returnVal>
</cffunction>

<cfscript>
 myCustomTag(a="b");
</cfscript>

Now, if you are using Railo, you could use the cfscript equivalent to the <cfmodule> tag:

<cfscript>
    module name="myCustomTag";
</cfscript>
Epigene answered 9/2, 2012 at 18:16 Comment(3)
Thanks Jake, just what I was looking for.Scorcher
Some would argue that tags are good for UI based actions and components are better suited to model/services. Therefore it's rare that one would have a need to do such a thing.Hadik
Valid point @Todd Sharp, I am re-writing an app with FW/1 and am having to deal with a bunch of pre-existing custom tags that are utilized by several other apps... you are right, if given the proper time I would re-write them as components.Scorcher
C
1

Update for 2021:

Recent versions of ColdFusion that have enhanced cfscript support will allow you to call a custom tag similar to a function.

<cf_custtag att1="value1" att2="value2">

equates to

<cfscript>    
    cf_custtag(att1="value1", att2="value2");
</cfscript>

I have not found a native solution to nesting custom tags or getting the generatedContent, so I made a workaround.

I pass content in to the custom tag using a custom attribute named "generatedContentOverride".

In the custom tag code, I look for that attribute and use it in place of thisTag.generatedContent.

Cineaste answered 1/10, 2021 at 18:44 Comment(1)
Thanks for posting this! I tested it and this syntax works as far back as ColdFusion 2016 update 17. It's referenced here helpx.adobe.com/coldfusion/cfml-reference/…Bluestone

© 2022 - 2024 — McMap. All rights reserved.