Javascript Abstraction in ColdFusion: Pro or Con?

There is an interesting article up on Ajaxian.com today discussing the pros and cons of Javascript abstractions. It's aimed squarely at the root of an issue that I have with ColdFusion 8's Ajax and Javascript integration: abstractions are easier and save time, but do you loose something by giving away that control? I heard Andy Powell give a talk at CFUnited in 2007 about the (then) upcoming release of ColdFusion 8 and its Ajax and JS support, where he asked the room to raise their hands if they liked Javascript. Those few of us that did got some weird looks from the crowd... how weird: people that use a technology might actually like it?

I like Javascript, and I don't think that thats weird. If I need FCKEditor in ColdFusion, I still use FCKEditor, rather then the new tags. If I need ExtJS, I still use ExtJS rather then the new tags. Why? Because I know that I can program better for my situation then Adobe. Its not that Adobe's code isn't good, its just that they have to program in such a way that it works for everyone, and that always creates bloat. Always.

Using <cfwindow> will save you some time, I'm not saying that it wont, but its going to add overhead that might not intend. You might not ever notice that overhead, and thats fine, but what happens if its a problem? Ultimately you'll have to go find someone that actually knows (and probably likes) Javascript to fix the problem for you. Why not get that person to write it in the first place?

Where would you draw the line? The purist in me says "Code it straight in JS and don't mess around." while the realist in me says "If most people don't need to rework the tags, then its working fine." Do you think abstraction can come back to bite you, or is it just a time saver?

 

Re: Overriding ColdFusion's ArgumentCollection

Ben Nadel found an interesting problem with ArgumentCollection, and I've done some additional tests that I find interesting. I was able to achieve the value fluctuation that Ben saw with only a single method based override on ColdFusion 8.0.1:


<!--- Trimmed down version of Ben's test function --->
<cffunction name="OutputArguments" output="true">
    <!--- Output arguments. --->
    <cfdump var="#ARGUMENTS#" label="From OutputArguments()"/>
</cffunction>


<!--- Define the argument collection. --->
<cfset objArgs = {
    Naomi = "Sweet",
    Kit = "Tough",
    Christina = "Cocky"
} /
>


<!---
    Invoke the test method using both the argument
    collection and an overriding value.
--->

<cfset OutputArguments(
    ArgumentCollection = objArgs,
    Naomi = "Wicked hot"
) /
>

Multiple refreshes saw the Naomi listed as "Sweet" more often then not. Ben had stated in his post that he saw fluctuations in value when using only a single CFINVOKE, but stable results with the method version. I'm sing the opposite; values seem constant when using CFINVOKE.


<!--- Trimmed down version of Ben's test function --->
<cffunction name="OutputArguments" output="true">
    <!--- Output arguments. --->
    <cfdump var="#ARGUMENTS#" label="From OutputArguments()"/>
</cffunction>


<!--- Define the argument collection. --->
<cfset objArgs = {
    Naomi = "Sweet",
    Kit = "Tough",
    Christina = "Cocky"
} /
>


<!---
    Invoke the test method using both the argument
    collection and an overriding value.
--->

<cfinvoke
    method="OutputArguments"
    argumentcollection="#objArgs#">


    <!--- Override argument. --->
    <cfinvokeargument name="Naomi" value="Very Cute" />
</cfinvoke>

Added examples on my site:

 

Utility Function: IfElse()

I don't know about you, but I hate having to write out simple if-else code bits in CF. Until they come out with a good operator like JS has (something?something:something), CF needs a simplification.

<cffunction name="IfElse" access="public" output="false" returntype="Any">
    <cfargument name="test" type="boolean" required="true" />
    <cfargument name="whenTrue" type="any" required="true" />
    <cfargument name="whenFalse" type="any" required="true" />
    
    <cfif ARGUMENTS.test>
        <cfreturn ARGUMENTS.whenTrue />
    <cfelse>
        <cfreturn ARGUMENTS.whenFalse />
    </cfif>    
</cffunction>

Seems pointless, but which would you rather read?

<!--- Classic, 5 lines --->
<cfif true>
    <cfset x = "dog" />
<cfelse>
    <cfset x = "cat" />
</cfif>

<!--- Version 2, 4 lines --->
<cfset x = "cat" />
<cfif true>
    <cfset x = "dog" />
</cfif>

<!--- My Way, 1 line --->
<cfset x = IfElse(true, "dog", "cat") />

 

Utility Function: GetInstanceName()

I can't claim the core of this function as my own, it comes from a presentation by Adam Lehman on ColdFusion server administration. I wrapped his code snippet into a function for reuse.

<cffunction name="GetInstanceName" access="public" output="false" returntype="string">        
    <cfreturn createObject("java", "jrunx.kernel.JRun").getServerName() />
</cffunction>

 

Utility Functions: ArrayRandomize()

A simple array randomization option. Note that although I use "CFMX_COMPAT" as the default randomization algorithm, you should probably always use "SHA1PRNG" to get better results.

<cffunction name="ArrayRandomize" access="public" output="true" returntype="array">
    <cfargument name="array" type="array" required="true" />
    <cfargument name="algorithm" type="string" required="false" default="CFMX_COMPAT" />
    
    <!---
        Fisher-Yates shuffle
        http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
     --->

    <cfset var i = ArrayLen(arguments.array) />
    <cfset var k = 0 />
    <cfset var temp = "" />
    
    <cfif i gt 0>
        <cfloop condition="i gt 0">
            <cfset k = RandRange(1, i, arguments.algorithm) />
            
            <cfset temp = arguments.array[i] />
            <cfset arguments.array[i] = arguments.array[k] />
            <cfset arguments.array[k] = temp />
            <cfset i = i - 1 />
        </cfloop>
    </cfif>
    
    <cfreturn arguments.array />
</cffunction>

 

Utility Function: RequireScript()

I'm not too happy with with this implementation, but I think it works out fairly well. Note that it uses the two functions in the related posts.

<cffunction name="RequireScript" access="public" output="false" returntype="void">
<cfargument name="script" type="string" required="true" />

<cfif NOT StructKeyExists(request, "__requirescript")>
        <cfset request["__requirescript"] = ArrayNew(1) />
    </cfif>
    <cfif NOT ArrayFind(request["__requirescript"], arguments.script)>
        <cfset ArrayAppend(request["__requirescript"], arguments.script) />
        <cfset IncludeScript(arguments.script) />
    </cfif>
    
<cfreturn />
</cffunction>

 

More Entries

Jon Hartmann, July 2011

I'm Jon Hartmann and I'm a Javascript fanatic, UX/UI evangelist and former ColdFusion master. I blog about mysterious error messages, user interface design questions, and all things baffling and irksome about programming for the web.

Learn more about me on LinkedIn.