Have you ever wondered how you could create JavaScript data from ColdFusion? Now before you say anything, I'm not talking about AJAX. While using AJAX to load data into the client is probably the most often used way to do this, it certainly isn't the only way. Consider the following example.
<cfset string= "Lindsey Lohan is a Cylon.">
<html>
<head>
<cfoutput>
<script>
var data = '#string#'
alert(data)
</script>
</cfoutput>
</head>
<body>
<h1>Demo</h1>
</body>
</html>
I've got a CFML variable, string, that I output within a script block. Because I'm working with a string, I surround the variable with single quotes. Double quotes would have worked as well. When run in the browser, the alert displays:

Woot. Nice and simple. Until someone goes and screws things up:
<cfset string= "Ray's neck is hurting today.">
This generates:
<script>
var data = 'Ray's neck is hurting today.'
alert(data)
</script>
Ouch. Obviously you could just wrap the output in double quotes, but if my ColdFusion variable had both single and double quotes, I'm screwed. We could use the jsStringFormat function.
<cfset string= "Ray's neck is hurting today. He said, ""I need to take some pills.""">
<html>
<head>
<cfoutput>
<script>
var data = '#jsStringFormat(string)#'
alert(data)
</script>
</cfoutput>
</head>
<body>
<h1>Demo</h1>
</body>
</html>
Notice now my string has both single and double quotes embedded in the variable. The jsStringFormat function handles it perfect. Here is how it outputs the variable:
var data = 'Ray\'s neck is hurting today. He said, \"I need to take some pill.\"'
Again, I say woot. But that's just a string. How would you convert an entire ColdFusion query into a JavaScript variable? Or an array? Or a struct? How about a struct that contains an array that contains a query that... err you get the idea. Let's take a look at a ridiculous example:
<cfset addresses = []>
<cfset addresses[1] = "403 Robinhood Circle, Lafayette, LA, 70508">
<cfset addresses[2] = "1801 Kaliste Saloom Rd, Lafayette">
<cfset addresses[3] = "400 Camellia Blvd, Lafayette, LA 70503">
<!--- Set of long/lats --->
<cfset longlats = []>
<cfset longlats[1] = {lat=30.09,long=-91.9}>
<cfset longlats[2] = {lat=30.08,long=-91.84}>
The code above generates an array of addresses, then an array of structures. ColdFusion provides us nice functions to introspect both arrays and structs (how do you think CFDUMP works?) so we could do this by hand, but luckily there is an even simpler solution: toScript. At it's simplest usage example, you provide it the data and the name of a JavaScript variable to create.
<cfoutput>
<script>
var #toScript(addresses,"addressesToPlot")#
var #toScript(longlats,"locations")#
</script>
</cfoutput>
Which outputs:
<code>
<script>
var addressesToPlot = new Array();
addressesToPlot[0] = "403 Robinhood Circle, Lafayette, LA, 70508";
addressesToPlot[1] = "1801 Kaliste Saloom Rd, Lafayette";
addressesToPlot[2] = "400 Camellia Blvd, Lafayette, LA 70503";
var locations = new Array();
locations[0] = new Object();
locations[0]["lat"] = "30.09";
locations[0]["long"] = -91.9;
locations[1] = new Object();
locations[1]["lat"] = "30.08";
locations[1]["long"] = -91.84;
</script>
Nice and simple, right? The docs mention that it supports strings, numbers, arrays, structs, and queries, but not CFCs. That's only partially true. You can pass a CFC to toScript, but it outputs broken code. This is what I got when I passed a CFC with two methods:
var apple = new Object();
apple["getfoo"] = apple["getentries"] =
It looks like it got the methods but didn't know what to do with them. Either way, hope this is useful.
Archived Comments
don't people use WDDX anymore?
<.cfwddx action="cfml2js"
No. ;) Seriously, good point, that's another way. Although I'd recommend toScript just because it is newer and shinier.
Wow, Ray, you've given me a new perspective on generating script. Thanks!
Up until now I've treated the creation of arrays by using value lists. For example:
<cfquery name="foo" datasource="dsn">
SELECT bar
FROM myTable
</cfquery>
<script>
var myArray = [<cfoutput>#ValueList(foo.bar)#</cfoutput>];
</script>
wish I had seen this about 6 weeks ago...
Just for what it's worth, you can also call .cfm file as an external script and it, assuming the output is formatted correctly, it will run as well.
For example:
<script type="text/javascript" src="generate_some_javascript.cfm?youcaneven=senddata"></script>
This way you can load some JavaScript-ready data without mucking up your display code.
One additional note about doing this however: I've found that if you use ColdFire for debugging this additional .cfm request seems to confuse it and you'll end up getting the debug info for that request.
ColdFire supports handling N CF requests in one main request, so make sure you are updated to the latest build. If you still see this, be sure to log a bug for it at RIAForge.
Will do, Ray.
@mgersting - You should see debugging info for the "parent" request as well as the JavaScript request. Check out the following post for more info: http://www.mischefamily.com...
One note, the UI has changed slightly since I recorded those demos, but the idea is the same.
Nathan - thanks for the tip. Turning off "Show Last Request" fixed the issue for me. Should I be able to to switch selected templates as in those screencasts, though?e
I learn more about CF everytime I read your blog ;)
This gives me a start and some idead into into generating dynamic javascript for dynamic form fields.
@mgersting - You should see a file name to the right of the "Variables" button. Click that to see a list of available responses to debug.