How can I include an external javascript file that contains coldfusion code?

10.1k views Asked by At

I have a few coldfusion files that use the same exact javascript code. I want to separate the javascript out into a .js file and include it in each of the files so that I don't have to repeat everything several times. So, I separated the javascript code into a file named "myPage.js", and in "myPage.cfm" I included a script tag -

<script language="javascript" src="myPage.js"></script>

The problem is that there's some coldfusion code spread among the javascript that injects values using <cfoutput>s and such, and that is no longer being translated correctly, probably because it's trying to read it as pure javascript. Is there any way I can have an external js file but indicate that I want it to use coldfusion to interpret it as well?

One workaround that I've found is to put the javascript into a coldfusion file instead of a javascript file, called "myPageJavascript.cfm", surround all the javascript code in a <script type="text/javascript"> tag, and then use a cfinclude to include that javascript in all the pages. This works fine, but it doesn't seem to me as intuitive as including a js file... What's the standard practice for situations like this? Is there any way to implement this as an external js file, or should I just stick to my coldfusion template file?

5

There are 5 answers

4
orangepips On BEST ANSWER

Other answers are more elegant and efficient, but the easy way out is change the file extension from .js to .cfm as such:

<script language="javascript" src="myPage.cfm?id=#createUuid()#"></script>

The createUuid() is there to prevent caching, assuming file output will differ, most likely based on variables from the session scope. The client loads this as JavaScript, while the server processes it as ColdFusion. You can do the same thing with style sheets as well.

Now, if your JavaScript depends on values from the calling page you can pass them along on the URL:

<script language="javascript" src="myPage.cfm?name1=value1&name2=value2"></script>

In this situation you can actually can take advantage of caching when the same URL parameters are passed.

Overall, this approach can be a lot less effort than refactoring code to keep the .js file "pure", while outputting variables it depends upon in a <script/> block beforehand.

0
mujimu On

What I liked at first about @Orangepips's answer over @Anooj's is the ease of future maintenance over requiring a separate Javascript block every time you included the <script> in your CFMs.

After a few minutes of thinking about it, however, this is easily eliminated by combining the two answers. This gives you modularity for ease of today's development and future maintenance that you seek -- PLUS as a best practice gives you isolation & caching of the static Javascript in order to decrease your CF page request size & response speed.

Basically you should create a CF-based facade that you will include or call every time you want the Javascript functionality. In my example, I made the facade a callable function that you can pass the JS params into (as @Orangepips was alluding to) in order to tightly control what vars get passed to the JS.

(As an aside, as a best practice, I tend to put all inline JS into variable then stuff it into CFHEADER, to assure it's in the page header.)

dosomething.js

<script type='text/javascript'>
    <!-- assert vars were passed in -->
    if ( source == undefined )
         alert("Developer error: source not defined.");
         return;
    }
    if ( urlpath == undefined )
         alert("Developer error: urlpath not defined.");
         return;
    }

    <!-- do some js stuff --->
    alert('source: ' + source + ", urlpath: " + urlpath );
</script>

udf.cfm:

<cffunction name="doSomething" output="true" returntype="void">
    <cfargument name="source" required="true" /> 
    <cfargument name="urlpath" required="true" /> 

    <cfsavecontent variable="header">
    <script type="text/javascript">
        <!-- var init -->
        <cfoutput>
            var source = '#arguments.source#';
            var urlpath = '#arguments.urlpath#';
        </cfoutput>
    </script>
    <script language="JavaScript" type="text/javascript" src="dosomething.js"></script>
    </cfsavecontent>
    <cfhtmlhead text="#header#">
</cffunction>

application.cfm

<cfinclude template="udf.cfm">

view1.cfm:

<cfoutput>#doSomething("view 1", "http://myurl/view1")#</cfoutput>

view2.cfm:

<cfoutput>#doSomething("view 2", "http://myurl/view2")#</cfoutput>

Any future changes become easier in having the code separated out (JS is separate from JS-var defining facade is separate from individual views calling it). E.g. in adding a variable, you could make it backwards compatible so all existing views continue to work.

udf.cfm changes:

<cfargument name="newVar" required="false" default="" /> 
<cfif len(arguments.newVar)>
var newVar = "#arguments.newVar#";
</cfif>

dosomething.js changes:

// keep JS backwards compatible
if ( newVar != undefined) {
    // new var was passed in, do something with it
}
// else, not passed in 
0
rsp On

It would be more efficient if you moved the ColdFusion code back to where you got it from, where you would use it to set some JavaScript variables, and leave only pure JavaScript which would then use those variables in your external JavaScript files. This would be the simplest solutions. Something more advanced would be to define functions in your external JavaScript files that would get called from your script tags in your ColdFusion-generated HTML.

3
Anooj On

I would suggest you create a script block prior to the js include which contains all the variables to be used inside the including js file. In your case, move those cfoutput variable you put inside the js file to the main file

    <script type='text/javascript'>
    var sourceName = <cfoutput>#Application.name#</cfoutput>
    </script>

    <script src="js/myPage.js" type="text/javascript"/>

In the myPage.js file you can use the variable sourceName which has the actuall value from the coldfusion variable. thus helping you from seperating coldfusion code and js code.

If you have a a lot of variables to be moved out, consider creating object type variable and add all those variable inside it.

NOTE : Adding js with script tag will help it cache and increase page performance. So do not load js file as cfm file

0
jwhooper On

To identify what came from the server, and to have the CF function toScript render the variables correctly, including structs and arrays, I use this method:

<script>
    var cf = {};
    <cfscript>
        writeOutput(toScript(application.applicationname,'cf.app'));
        writeOutput(toScript(cgi.remote_addr,'cf.url'));
    </cfscript>
</script>

renders to:

<script>
    var cf = {};
    cf.app="Lucee";cf.url="149.79.80.135";
</script>

and now in your external .js you just use cf.app, cf.url ... and so on.

It can be very convenient sometimes to pass along the URL struct on a get or FORM struct on a post.