Convert a ColdFusion Query into a JSON Object
Jul 12 |
I have used various HTML5 widgets extensively for the last decade and will share the functions I use to convert ColdFusion objects returned from a database into JSON. In this article, I will highlight some of the logic in the code and show you how to use this for various use cases.
Table of Contents
What Does This Component Do?
These functions are critical components of all of my HTML5 applications. They convert both a ColdFusion query and a ColdFusion ORM array object into JSON that is passed back to the calling Ajax function. Unlike ColdFusion's native JSON functions, this will return the column names in the proper case rather than in uppercase.
Adrian Moreno created the function. I modified it nearly a decade ago, and it has been in use in several production environments over the last ten years. It is also used extensively in my open-source Galaxie Blog, which is an HTML5 application. These two functions have been tested thoroughly and have handled server-side data operations on nearly every jQuery-based HTML5 widget I have used.
There may be something in the CF world that is a little more modern than this. However, I have written these functions to handle the everyday use cases I have found when preparing JSON data. For example, some widgets want a data handle in the JSON, while others don't. These functions have handled all use cases that I have thrown at them when using Kendo UI and have handled other HTML5 libraries, such as jsGrid. I have tested a dozen similar functions, and this approach offered the best performance.
I also use this component extensively in my how-to ColdFusion and Kendo blog series. Please download this component if you are working with Kendo UI while reading this series.
Download the CFJson Component from GitHub
This component can be found on GitHub at https://github.com/GregoryAlexander77/CfJson. It has been tested on ColdFusion 10 through the most modern ColdFusion version, CF2021.
Working with ColdFusion Queries
When dealing with a native ColdFusion query object, use the convertCfQuery2JsonStruct function to convert it into JSON. This function takes a native ColdFusion query object and converts it into JSON.
There are several arguments; the queryObj is required, and the rest are optional.
Function Arguments
- queryObj (required)
Pass in the name of the ColdFusion query. This must be a ColdFusion query object. - contentType
Default value: json
This argument, for now, is always set to json. This argument was put into the function as eventually, I hope to add JSONP support. - includeDataHandleName
Default value: false
This inserts a data handle in front of the JSON. It is used for special use cases when using the Kendo widgets, and also is used for other HTML libraries, such as jsGrid. - dataHandleName
Default value: false
Specify your data handle name when setting the includeDataHandle argument to true. - includeTotal
Default value: false
Used for the Kendo Grids and for Pagination. - overRideTotal
Default value: false
Used for pagination when filtering records in a Kendo Grid. - newTotal
Default value: false
Used to indicate the total number of records after applying filters to a Kendo Grid. - removeStringHtmlFormatting
Default value: false
Removes HTML and special characters in the JSON. This is used to create a sanitized string that is displayed in a grid (works with both Kendo and jsGrid grids) - columnThatContainsHtmlStrings
default value: empty string
When removeStringHtmlFormatting is set to true, specify the column that you want to be sanitized. - convertColumnNamesToLowerCase
Default value: empty string
This argument is rarely used. In certain situations, you may want to force all of the JSON element names to a lower case to avoid any case sensitivity issues.
Example ColdFusion Query
Here is a simple query that grabs the Galaxie Blog built-in roles. We get the role ID, name, and description and output this to JSON to populate our HTML5 widgets.
After obtaining the data, we will pass the name of this query, Data, to the convertCfQuery2JsonStruct method to convert this ColdFusion query into a JSON string. This query will be used for all examples below using the convertCfQuery2JsonStruct method that converts a ColdFusion query object into a JSON object.
Note: I am only getting the top two records to make it easier to view the JSON output below.
<!--- Make the query --->
<cfquery name="Data" datasource="#dsn#">
SELECT TOP 2 RoleId
,RoleName
,Description
FROM Role
</cfquery>
Common Usage Using Default Settings
This takes the ColdFusion query object that we just made, in this case, "Data", and it converts it into JSON without a total data handle or any special formatting.
This particular usage supports most Kendo Widgets, other than the Kendo Grid or other specialized use cases. All of the different arguments are set by default and are not used.
<!--- Convert the query object into JSON using the default parameters of convertCfQuery2JsonStruct method --->
<cfinvoke component="#application.cfJsonComponentPath#" method="convertCfQuery2JsonStruct" returnvariable="jsonString" >
<cfinvokeargument name="queryObj" value="#Data#">
</cfinvoke>
This is what the JSON that the function returns when using the default arguments:
[
{
"Description":"All functionality.",
"RoleId":1,
"RoleName":"Administrator"
},
{
"Description":"Can create and edit their own posts.",
"RoleId":2,
"RoleName":"Author"
}
]
Getting the JSON with a Data Handle
If you need to use a data handle, use the following arguments:
<!--- Convert the query object into JSON --->
<cfinvoke component="cfJson" method="convertCfQuery2JsonStruct" returnvariable="jsonString" >
<cfinvokeargument name="queryObj" value="#Data#">
<cfinvokeargument name="contentType" value="json">
<cfinvokeargument name="includeTotal" value="false">
<!--- Don't include the data handle for Kendo grids --->
<cfinvokeargument name="includeDataHandle" value="true">
<cfinvokeargument name="dataHandleName" value="myData">
<!--- Set to true to force the column names into lower case. --->
<cfinvokeargument name="convertColumnNamesToLowerCase" value="false">
</cfinvoke>
Using this Function with ColdFusion ORM HQL Query
This component also works when using ColdFusion ORM using the convertHqlQuery2JsonStruct method. This method is identical to the convertCfQuery2JsonStruct method; the only difference is that it takes an HQL query object instead of a native ColdFusion query.
Example ColdFusion HQL Query
I won't go into the details of using HQL, but here, we use the map keyword in HQL to return an array of Java HashMaps. This query should be understandable to ColdFusion developers; it looks nearly the same as using cfquery.
<cfquery name="Data" dbtype="hql">
SELECT new Map (
RoleId as RoleId,
RoleName as RoleName,
Description as Description
)
FROM
Role as Role
</cfquery>
Function Output
Here is what the function returns:
[
{
"blogurl":"https://www.gregoryalexander.com/blog/",
"blogdescription":"A technical blog powered by Galaxie Blog - the most beautiful and functional open source ColdFusion/Kendo UI based blog in the world.",
"blog":"Gregory's Blog"
}
]
Using this Function to Populate Kendo Virtual Grids
The convertCfQuery2JsonStructForVirtualGrid method is used when populating Kendo Virtual Grids. This particular function is similar to our other functions. However, the default usage will include the data handle and override the total if a new query is made. You can force the columns to be returned in lowercase; however, the default setting returns the column names from the ColdFusion query object as they exist in the database.
The following arguments are typically used to invoke this component for virtual grids:
<!--- Using my jsonArray.cfc --->
<cfinvoke component="#application.cfJsonComponentPath#" method="convertCfQuery2JsonStructForVirtualGrid" returnvariable="jsonString" >
<cfinvokeargument name="queryObj" value="#data#">
<cfinvokeargument name="includeTotal" value="true">
<!--- When we use server side paging, we need to override the total and specify a new total which is the sum of the entire query. --->
<cfinvokeargument name="overRideTotal" value="true">
<!--- We set the totalNumRecords near the top of the function, however, if the filters were applied, the new total will be the number of records in the data query object. --->
<cfif searchFilter>
<cfset totalRecords = data.recordcount>
<cfelse>
<cfset totalRecords = totalNumRecords>
</cfif>
<cfinvokeargument name="newTotal" value="#totalRecords#">
<!--- The includeDataHandle is used when the format is json (or jsonp), however, the data handle is not included when you want to make a javascript object embedded in the page. --->
<cfinvokeargument name="includeDataHandle" value="true">
<!--- If the data handle is not used, this can be left blank. If you are going to use a service on the cfc, typically, the value would be 'data'--->
<cfinvokeargument name="dataHandleName" value="data">
<!--- Keep the case of the columns the same as the database --->
<cfinvokeargument name="convertColumnNamesToLowerCase" value="false">
</cfinvoke>
<cfreturn jsonString>
Function Output
The following is an example output for our World Cities Virtual Grid when the initial grid is rendered. Notice that the total handle is included and the data handle is present:
{"total":129943,"data":[{"Currency":"AFN","CityFlag":1,"CityId":50,"CountryId":1,"Longitude":65.00000000,"CityLongitude":65.123760,"CurrencyName":"Afghan afghani","State":"Faryab","Flag":1,"ISO3":"AFG","ISO2":"AF","RowNumber":1,"StateFlag":1,"City":"Andkhoy","Country":"Afghanistan","StateId":3889,"CityLatitude":36.952930,"Latitude":33.00000000,"Type":"","Capital":"Kabul"},{"Currency":"AFN","CityFlag":1,"CityId":51,"CountryId":1,"Longitude":65.00000000,"CityLongitude":71.146970,"CurrencyName":"Afghan afghani","State":"Kunar","Flag":1,"ISO3":"AFG","ISO2":"AF","RowNumber":2,"StateFlag":1,"City":"Asadabad","Country":"Afghanistan","StateId":3876,"CityLatitude":34.873110,"Latitude":33.00000000,"Type":"","Capital":"Kabul"},{"Currency":"AFN","CityFlag":1,"CityId":52,"CountryId":1,"Longitude":65.00000000,"CityLongitude":71.533330,"CurrencyName":"Afghan afghani","State":"Badakhshan","Flag":1,"ISO3":"AFG","ISO2":"AF","RowNumber":3,"StateFlag":1,"City":"Ashk?sham","Country":"Afghanistan","StateId":3901,"CityLatitude":36.683330,"Latitude":33.00000000,"Type":"","Capital":"Kabul"},{"Currency":"AFN","CityFlag":1,"CityId":53,"CountryId":1,"Longitude":65.00000000,"CityLongitude":68.015510,"CurrencyName":"Afghan afghani","State":"Samangan","Flag":1,"ISO3":"AFG","ISO2":"AF","RowNumber":4,"StateFlag":1,"City":"A?bak","Country":"Afghanistan","StateId":3883,"CityLatitude":36.264680,"Latitude":33.00000000,"Type":"","Capital":"Kabul"},{"Currency":"AFN","CityFlag":1,"CityId":54,"CountryId":1,"Longitude":65.00000000,"CityLongitude":68.708290,"CurrencyName":"Afghan afghani","State":"Baghlan","Flag":1,"ISO3":"AFG","ISO2":"AF","RowNumber":5,"StateFlag":1,"City":"Baghl?n","Country":"Afghanistan","StateId":3875,"CityLatitude":36.130680,"Latitude":33.00000000,"Type":"","Capital":"Kabul"}]}
For more information regarding Kendo virtual grids, please see Implementing a Kendo Virtualized Grid with ColdFusion - Part 2, Server-Side Logic
Further Reading
- ArrayCollection.cfc, a custom JSON renderer for ColdFusion queries (by Adrian Moreno)
- Ask Ben: Converting a Query to an Array
- (CF)JSON - My Own ColdFusion Version For AJAX (Ben Nadel, written in 2006)
- Format JSON string in ColdFusion (Chad's Tech Blog)
Updated 6/14/2023
Related Entries
- Benefits of ColdFusion and Kendo UI
- The Different Flavors of Kendo UI and Kendo Licensing Terms
- Incorporate Kendo UI into a ColdFusion Application
- Using ColdFusion to Populate Kendo UI Widgets
- Introducing the various forms of Kendo Dropdowns
- Working with JSON and JavaScript
- Cascading Kendo MultiSelect Dropdowns
- Introducing the Kendo Grid
- A Comprehensive Analysis of the Editable Kendo UI Grid
- Implementing a Kendo Virtualized Grid with ColdFusion - Part 2, Server-Side Logic
- Handling Server-Side Errors with ColdFusion and JSON
Tags
ColdFusion and Kendo UI, ColdFusion and Kendo UIThis entry was posted on July 12, 2022 at 11:40 PM and has received 2890 views.