(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 »
10,640 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 »
10,640 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 »
10,640 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 »
11 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
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 12, 2012 at 3:37 AM
Learning ColdFusion 8: CFImage Part III - Watermarks And Transparency
Hi Ben, Just to ask currently it is placed bottom right corner, if i need to replace the same rendered image on the bottom left side or in the bottom center, how that can be calculated. bottom ce ... read »
Feb 11, 2012 at 9:29 PM
Use jQuery's SlideDown() With Fixed-Width Elements To Prevent Jumping
I can't say how glad I am that I found your post. Thank you very much. ... read »
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »