(CF)JSON - My Own ColdFusion Version For AJAX

Posted June 27, 2006 at 8:42 AM

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:

 Launch code in new window » Download code as text file »

  • <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>

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page



Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

tberg
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 »
6,371 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 »
6,371 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.


John
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!


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

Thanks Ben!


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 7, 2009 at 5:53 PM
Ask Ben: Javascript String Replace Method
You can find here an advanced function that prepared with javascript replace function. This can make the first letters of words, sentences, lines and whatever you define automatically: http://www.m ... read »
Andrew Neely
Nov 7, 2009 at 4:56 PM
A Moment That Touched Me - The Fountainhead
Ben, Glad you enjoyed the podcast. Yeah, the Tank Riot guys can get really chatty during the episodes, but that's part of the charm of it for me. They've covered everything from Nichola Tesla to Cha ... read »
Nov 7, 2009 at 4:43 PM
Building A Fixed-Position Bottom Menu Bar (ala FaceBook)
Is it possible to make some more MenĂ¼`s ? ... read »
Jill
Nov 7, 2009 at 11:40 AM
How To Unformat Your Code (Like A Pro)
Derek, I think you might be right - sweet! Thanks for the link :) ... read »
Nov 7, 2009 at 11:25 AM
How To Unformat Your Code (Like A Pro)
I think it would be way easier to just use this http://www.logichammer.com/html-formatter/ He just released v3 and it rocks. ... read »
Jill
Nov 7, 2009 at 7:58 AM
How To Unformat Your Code (Like A Pro)
LMAO - this was pretty funny! I have to admit - I also love to reformat code so I can read it. My boss used to tell me to leave my OCD at home. Now I don't feel so bad after reading everyone else' ... read »
Nov 6, 2009 at 10:10 PM
How To Unformat Your Code (Like A Pro)
The timing of this post is just uncanny. I spent the last 15-20 minutes manually un-formatting my "Ben Nadel" style code within a CFC of mine. I was really digging the readability a few weeks ago, bu ... read »
Roe
Nov 6, 2009 at 5:11 PM
Passing Arrays By Reference In ColdFusion - SWEEET!
ArraySort also reorders the results of these java obj's ... read »