(CF)JSON - My Own ColdFusion Version For AJAX

Posted June 27, 2006 at 8:42 AM by Ben Nadel

Tags: ColdFusion, AJAX

After going through CFJSON, I created my own version with my own coding standards and quirkiness. To point out some non-superficial changes, my version:

Does not have any try-catch blocks. I don't get the point. I don't see where the code can really fail. I am only checking standard types that should have standard values. I can't see what would break.

For the query conversion, I am not including the column list or the recordcount. I think that's pointless. I am not interested in the meta-data. I only want the records. I honestly cannot think of any situation where I would not know what columns I was dealing with before I even made the AJAX call to the ColdFusion server.

Another query conversion difference is that fact that my query is returned as an array of "row" structures rather than CFJSON's array of "column" structures. I am not crazy about ColdFusion's implementation direct access query notation and I don't want to carry that over to the Javascript side of things. The down side of this is that my conversion returns more data as the column names are repeated keys for each record of the query. I don't think this is such a huge issue though as I do not intend to deal with massive amounts of data.

So, without further delay, my version of CFJSON:

  • <cffunction name="ToJavascript" access="public" returntype="string" output="false"
  • hint="Based on CFJASON {http://jehiah.com/projects/cfjson/}, this converts ColdFusion structures to Javascript Object Notation.">
  •  
  • <cfargument name="Data" type="any" required="yes" />

  • <cfscript>

  • // Define the local scope.
  • var LOCAL = StructNew();

  • // Create an object to store the output. We are going to use
  • // a java string buffer as there may be a large amount of
  • // concatination.
  • LOCAL.Output = CreateObject( "java", "java.lang.StringBuffer" ).Init();

  • // Check to see if the data is an array.
  • if (IsArray( ARGUMENTS.Data )){

  • // Loop over the array to encode the items.
  • for (LOCAL.Index = 1 ; LOCAL.Index LTE ArrayLen( ARGUMENTS.Data ) ; LOCAL.Index = (LOCAL.Index + 1)){

  • // Encode the value at this index. Call the function
  • // recursively as this could be any kind of data.
  • LOCAL.Value = ToJavascript( ARGUMENTS.Data[ LOCAL.Index ] );

  • // Check to see if we are appending to a current value.
  • if (LOCAL.Output.Length()){
  • LOCAL.Output.Append( "," );
  • }

  • // Append the encoded value.
  • LOCAL.Output.Append( LOCAL.Value );

  • }

  • // Return the encoded values in an array notation.
  • return( "[" & LOCAL.Output.ToString() & "]" );

  • // Check to see if we have a structure.
  • } else if (IsStruct( ARGUMENTS.Data )){

  • // Check to see if the structure is empty. If it is, then
  • // we don't have to do any more work, just return the
  • // empty object notation.
  • if (StructIsEmpty( ARGUMENTS.Data )){
  • return( "{}" );
  • }

  • // Get the array of keys in the structure.
  • LOCAL.Keys = StructKeyArray( ARGUMENTS.Data );

  • // Loop over the keys in the structure.
  • for (LOCAL.Index = 1 ; LOCAL.Index LTE ArrayLen( LOCAL.Keys ) ; LOCAL.Index = (LOCAL.Index + 1)){

  • // Encode the value at this index. Call the function
  • // recursively as this could be any kind of data.
  • LOCAL.Value = ToJavascript( ARGUMENTS.Data[ LOCAL.Keys[LOCAL.Index] ] );

  • // Check to see if we are appending to a current value.
  • if (LOCAL.Output.Length()){
  • LOCAL.Output.Append( "," );
  • }

  • // Append the encoded value.
  • LOCAL.Output.Append( """" & LCase( LOCAL.Keys[LOCAL.Index] ) & """:" & LOCAL.Value );

  • }

  • // Return the encoded values in an object notation.
  • return( "{" & LOCAL.Output.ToString() & "}" );

  • // Check to see if this is some sort of other object.
  • } else if (IsObject( ARGUMENTS.Data )){

  • // We found an object that is not a built in type...
  • // return an unknown type.
  • return( "unknown-obj" );

  • // Check to see if we have a simple, numeric value.
  • } else if (IsSimpleValue( ARGUMENTS.Data ) AND IsNumeric( ARGUMENTS.Data )){

  • // Return the number as a string.
  • return( ToString( ARGUMENTS.Data ) );

  • // Check to see if we have a simple value.
  • } else if (IsSimpleValue( ARGUMENTS.Data )){

  • // Return the value encoded for Javascript.
  • return( """" & JSStringFormat( ToString( ARGUMENTS.Data ) ) & """" );

  • // Check to see if we have a query.
  • } else if (IsQuery( ARGUMENTS.Data )){

  • // We are going to convert the query into an array or
  • // structures. This is going to be somewhat slower than
  • // going straight from the query to javascript, but I
  • // think it will make the query more usable.

  • // Start by getting an array of the columns.
  • LOCAL.Columns = ListToArray( ARGUMENTS.Data.ColumnList );

  • // Create an array for the value.
  • LOCAL.TempData = ArrayNew( 1 );

  • // Loop over the rows in the query to create structures.
  • for (LOCAL.RowIndex = 1 ; LOCAL.RowIndex LTE ARGUMENTS.Data.RecordCount ; LOCAL.RowIndex = (LOCAL.RowIndex + 1)){

  • // Create a structure for the current row.
  • LOCAL.TempRow = StructNew();

  • // Loop over the columns to add values to the strucutre.
  • for (LOCAL.Column = 1 ; LOCAL.Column LTE ArrayLen( LOCAL.Columns ) ; LOCAL.Column = (LOCAL.Column + 1)){

  • // Add the column value to the structure.
  • LOCAL.TempRow[ LOCAL.Columns[ LOCAL.Column ] ] = ARGUMENTS.Data[ LOCAL.Columns[ LOCAL.Column ] ][ LOCAL.RowIndex ];

  • }

  • // Append the structure to the data array.
  • ArrayAppend( LOCAL.TempData, LOCAL.TempRow );

  • }

  • // ASSERT: At this point, we have converted the query
  • // into array of structs. Now encode it.

  • // No need to return with object notation since the JS
  • // encoding of the array will take care of that for us.
  • return( ToJavascript( LOCAL.TempData ) );

  • // Check for default case.
  • } else {

  • // If we got this far, then we found a type that we
  • // are not able to serialize.
  • return( "unknown" );

  • }

  • </cfscript>
  • </cffunction>


Reader Comments

May 31, 2007 at 3:16 PM // reply »
1 Comments

nice work! I'm already using your code in production. Serializing rows instead of columns is exactly the way to go.


May 31, 2007 at 3:22 PM // reply »
11,238 Comments

@tberg,

Check out the code from this post:

http://www.bennadel.com/index.cfm?dax=blog:588.view

It has the most up-to-date ColdFusion JSON code. I think it has been modified a bit since this post. Glad you like what I am doing.


Oct 8, 2007 at 11:02 AM // reply »
1 Comments

Year ago I was trying to create own framework for working with AJAX too, but now I understood that it is easily to use Prototype and more easier create other projects with it.


Jan 19, 2008 at 12:23 PM // reply »
1 Comments

Thanks for this work, Ben
Can I try to insert this code in few my projects?

Thanks beforehand!


Jan 19, 2008 at 11:37 PM // reply »
11,238 Comments

@Alexandr,

Go for it. Enjoy.


Mar 23, 2008 at 7:33 AM // reply »
1 Comments

nice work! I'm already using your code in production. Serializing rows instead of columns is exactly the way to go.


Jul 3, 2008 at 9:44 PM // reply »
1 Comments

Thanks Ben. Am using this to feed Yahoo's YUI library from CF7. I tried CFJSON first but couldn't work out how to tell YUI that the data was in columns. That became a no-brainer when delivered as rows.

Great work. Might be an old post, but still giving mileage.


Jul 17, 2008 at 8:31 AM // reply »
6 Comments

Thanks Ben!


Aug 6, 2008 at 7:42 AM // reply »
6 Comments

Thanks Ben!


Mar 10, 2010 at 12:33 PM // reply »
1 Comments

Thanks, Ben! I was banging my head against this for a bit - you've saved me a flat spot on my forehead.


Mar 10, 2010 at 9:21 PM // reply »
11,238 Comments

@Todd,

My pleasure good man. If you are using ColdFusion 8+, however, there are more easy ways of doing this, using the SerializeJSON() method.


Nov 24, 2010 at 11:40 PM // reply »
12 Comments

@all, toJavascript() will actually will escape single quotes which will generate invalid JSON (single quotes should not be escaped in JSON)

To fix this I just unescape the single quotes in Bens code with something like this:

  • replace(ToJavascript( whatevervar),"\'","'","ALL")

Hope this helps


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools