(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,246 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,246 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,246 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 23, 2013 at 9:52 PM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Muhmmadibn Did you figure out a solution to launching PDFs? I am running into the same issues myself. There is no way to close the PDF or go back once you launch it. Thanks in advance! ... read »
May 23, 2013 at 6:06 PM
The Girl Who Broke My Heart, And Made Me A Better Person
Good day,ladies and gentle men, my name is Dr AMADI the great spell caster in Africa, i have help so many people for different kind of problems,who say there is no solution to problems on earth, that ... read »
May 23, 2013 at 4:26 PM
ColdFusion QueryAppend( qOne, qTwo )
@Heather, Glad people are still getting value out of this! ... read »
May 23, 2013 at 3:49 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, I meant the code at the bottom (not the video). I did try to experiment with an intermediary variable, like: value = users.id[ i ]; arrayContains( userIDs, value ); ... but t ... read »
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
May 23, 2013 at 9:55 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dan, According to the CF Admin, I'm running Java "1.6.0_45". As far as the DB column, in the database it's an INT. I'll see if I can dig into what CF sees it as. @WebManWalking, But h ... read »
May 23, 2013 at 9:49 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, I think the problem is that we're used to loose typing in ColdFusion, like JavaScript. If a value is a number but it's needed in an expression to be a string, noooo problem. I've encountered ... read »
May 23, 2013 at 9:47 AM
ColdFusion QueryAppend( qOne, qTwo )
You rock! Thank you, thank you, thank you!!! ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools