I've been trying to create a data structure, but I'm having a hard time. I am trying to create a data structure like this:
{
"vehicle": [
{
"inv_id": "123412",
"year": "2013",
"make": "Jeep",
"model": "Grand Cherokee"
},
{
"inv_id": "1224522",
"year": "2013",
"make": "Jeep",
"model": "Grand Cherokee"
}
]
}
Here is what I've tried with no luck.
<cfset result["vehicle"] = []>
<cfoutput>
<cfloop query="qinv">
#arrayAppend("result.vehicle,{})#
<cfloop array="#result.vehicle#" index="i">
#structInsert(result.vehicle[i], "inventory_id", qInv.inventory_id)#
#structInsert(result.vehicle[i], "year", qInv.year)#
#structInsert(result.vehicle[i], "make", qInv.make)#
#structInsert(result.vehicle[i], "model", qInv.model)#
</cfloop>
</cfloop>
</cfoutput>
This is throwing a coldfusion error, The value coldfusion.runtime.Struct cannot be converted to a number. on the first structInsert line.
Any suggestions?
You don't need that array loop... think about it: what are you looping over? It's an empty array. All you need to do is append the struct to the array:
<cfset arrayAppend( result.vehicle,{
"inventory_id" = qInv.inventory_id,
"year" = qInv.year,
"make" = qInv.make,
"model" = qInv.model
})>
Related
I have a cfc where i need t return the headers for the jqgrid for binding dynamically
i am trying to query the data like this:
colNames: ['ID', 'Institution Name', 'Display Name', 'Short Name', 'Board of Education', 'Scheme Name','Subscription Date'],
colModel: [
{ name: 'institutionid', sortable: true, },
{ name: 'institutionname', sortable: true },
{ name: 'displayname', sortable: true },
{ name: 'shortname' ,sortable: true},
{ name: 'supportedfield', sortable: true },
{ name: 'schemename', sortable: true },
{ name: 'subscriptionto', sortable: true}
]
i can easily get the colNames, but for colmodal how can i bring the elements of sort: true for all by default and format should be like arrayofstructs
Thanks
Query try
<cffunction name="headers" localmode="modern" access="remote" returnformat="json" hint="Handles the Functionality of returning the Table Headers">
<cfset columnsInfos = {}>
<cfset returnArray = []>
<cfset cList = QueryExecute("select top 1 * from mytable").columnList>
<cfset cListQueryObj = QueryNew(cList)>
<cfdump var="#cListQueryObj#" abort>
<cfset colNames = ListtoArray(cList)>
<cfloop query="#cListQueryObj#">
<cfset rowStruct = {}>
<cfloop list="#cList#" index="colname">
<cfset "rowStruct['#colname#']" = cListQueryObj[colname]>
</cfloop>
<cfset arrayAppend(returnArray,rowStruct)>
<cfdump var="#rowStruct#">
</cfloop>
<cfset columnsInfos["colModel"] = returnArray>
<cfset columnsInfos["colNames"] = colNames>
<cfreturn columnsInfos>
</cffunction>
Serializing a query object won't return the expected result. Since you are using the built-in returnFormat="json", the easiest (and probably only) approach is working with an array of structs, just like your JS example shows:
<cffunction name="headers" localmode="modern" access="public" returnformat="json" hint="Handles the Functionality of returning the Table Headers">
<!--- best practise: declare the returned scheme --->
<cfset result = {
"colNames": [],
"colModel": []
}>
<!--- get your table's columns (mockup) --->
<cfset columnList = "institutionid,institutionname,displayname,shortname,supportedfield,schemename,subscriptionto">
<!--- use the column names from your query? --->
<cfset result["colNames"] = listToArray(columnList)>
<!--- add an entry with "name" and "sortable" for every column --->
<cfloop list="#columnList#" index="columnName">
<cfset result["colModel"].add({
"name": columnName,
"sortable": true
})>
</cfloop>
<cfreturn result>
</cffunction>
Note that we are not calling serializeJSON on the result, because returnFormat="json" will already do that for us. Regarding your colNames: Your JS example uses mapped column names, not dynamic ones as shown in your code and the code above. You might want to make them either static or map them yourself.
I like Alex's approach, but I like cfscript better. I also like localized variables.
<cfscript>
/**
* #hint Handles the Functionality of returning the Table Headers
* #output false
* #returnFormat JSON
*/
public any function headers() {
// best practise: declare the returned scheme
var result = {
"colNames": [],
"colModel": []
};
// get your table's columns (mockup)
var columnList = "institutionid,institutionname,displayname,shortname,supportedfield,schemename,subscriptionto";
// use the column names from your query?
result.colNames = listToArray(columnList);
// add an entry with "name" and "sortable" for every column
for (var columnName in columnList) {
result.colModel.add({
"name": columnName,
"sortable": true
});
}
return result;
}
writedump(headers);
writedump(headers());
</cfscript>
Function signature
Function results
Also see
JSON response using cfscript function
I have the following function, inherited from some CF code. It works, but only in ColdFusion version 10 and 11. I am not concerned with 2016 as no plans for upgrade. I'm trying to run it under Lucee, but it is not working.
<cffunction name="QueryToArray" access="public" returntype="array" output="false" hint="This turns a query into an array of structures.">
<!--- Define arguments. --->
<cfargument name="Data" type="query" required="yes" />
<cfscript>
var LOCAL = StructNew(); // Define the local scope.
LOCAL.Columns = data.getMetaData().getColumnLabels(); // Get the column names as an array.
LOCAL.QueryArray = ArrayNew(1); // Create an array that will hold the query equivalent.
for (LOCAL.RowIndex = 1 ; LOCAL.RowIndex LTE ARGUMENTS.Data.RecordCount;
LOCAL.RowIndex = (LOCAL.RowIndex + 1)){
LOCAL.Row = StructNew();
for (LOCAL.ColumnIndex = 1 ; LOCAL.ColumnIndex LTE ArrayLen(LOCAL.Columns);
LOCAL.ColumnIndex = (LOCAL.ColumnIndex + 1)){
LOCAL.ColumnName = LOCAL.Columns[LOCAL.ColumnIndex];
LOCAL.Row[LOCAL.ColumnName] = ARGUMENTS.Data[LOCAL.ColumnName][LOCAL.RowIndex];
}
ArrayAppend(LOCAL.QueryArray, LOCAL.Row);
}
return(LOCAL.QueryArray);
</cfscript>
</cffunction>
In Lucee, I tried making these changes:
<cffunction name="QueryToArray" access="public" returntype="array" output="false" hint="This turns a query into an array of structures.">
<!--- Define arguments. --->
<cfargument name="Data" type="query" required="yes" />
<cfscript>
var LOCAL = StructNew(); // Define the local scope.
LOCAL.Columns = data.getColumnlist(false); // Get the column names as an array.
LOCAL.QueryArray = ArrayNew(1); // Create an array that will hold the query equivalent.
for (LOCAL.RowIndex = 1 ; LOCAL.RowIndex LTE ARGUMENTS.Data.RecordCount;
LOCAL.RowIndex = (LOCAL.RowIndex + 1)){
LOCAL.Row = StructNew();
for (LOCAL.ColumnIndex = 1 ; LOCAL.ColumnIndex LTE ArrayLen(LOCAL.Columns);
LOCAL.ColumnIndex = (LOCAL.ColumnIndex + 1)){
LOCAL.ColumnName = LOCAL.Columns[LOCAL.ColumnIndex];
LOCAL.Row[LOCAL.ColumnName] = ARGUMENTS.Data[LOCAL.ColumnName][LOCAL.RowIndex];
}
ArrayAppend(LOCAL.QueryArray, LOCAL.Row);
}
return(LOCAL.QueryArray);
</cfscript>
</cffunction>
but I'm getting this error:
Message: Can't cast String [name,value] to a value of type [Array]
Detail: Java type of the object is java.lang.String
Stacktrace:
The Error Occurred in
C:\home\website\wwwroot\controller\production\cfc\kernel.cfc: line 12
10: LOCAL.RowIndex = (LOCAL.RowIndex + 1)){
11: LOCAL.Row = StructNew();
12: for (LOCAL.ColumnIndex = 1 ; LOCAL.ColumnIndex LTE ArrayLen(LOCAL.Columns);
13: LOCAL.ColumnIndex = (LOCAL.ColumnIndex + 1)){
14: LOCAL.ColumnName = LOCAL.Columns[LOCAL.ColumnIndex];
To get your code to work, all you need to do is change line 6 from
LOCAL.Columns = data.getColumnlist(false); // Get the column names as an array.
to this
LOCAL.Columns = data.getColumnNames(); // Get the column names as an array.
However I found a gist here that works in both ColdFusion and Lucee. I decided to create some sample code and test it at https://trycf.com/. I verified that it works in Lucee 4.5 and 5. It also works in ColdFusion 10, 11, 2016 as well. Hope this helps!
<!--- Create a new three-column query, specifying the column data types --->
<cfset myQuery = QueryNew("Name, Time, Advanced", "VarChar, Time, Bit")>
<!--- Make two rows in the query --->
<cfset QueryAddRow(MyQuery, 2)>
<!--- Set the values of the cells in the query --->
<cfset QuerySetCell(myQuery, "Name", "The Wonderful World of CMFL", 1)>
<cfset QuerySetCell(myQuery, "Time", "9:15 AM", 1)>
<cfset QuerySetCell(myQuery, "Advanced", False, 1)>
<cfset QuerySetCell(myQuery, "Name", "CFCs for Enterprise
Applications", 2)>
<cfset QuerySetCell(myQuery, "Time", "12:15 PM", 2)>
<cfset QuerySetCell(myQuery, "Advanced", True, 2)>
<h4>The query</h4>
<cfdump var="#myQuery#">
<h4>The array of objects</h4>
<cfset myArray = QueryToArray(myQuery)>
<cfdump var="#myArray#">
<cfscript>
/**
* #hint Returns reasonable array of objects from a cfquery
*/
public function queryToArray(
required query query,
string excludeColumns = ""
){
if (server.coldfusion.productName == "ColdFusion Server") {
local.columns = arguments.query.getMetaData().getColumnLabels();
} else if (server.coldfusion.productName == "Lucee") {
local.columns = arguments.query.getColumnNames();
} else {
local.columns = [];
}
local.response = arrayNew(1);
for (local.rowIndex=1; local.rowIndex<=arguments.query.recordCount; local.rowIndex++) {
local.response[local.rowIndex] = structNew();
for (local.columnIndex=1; local.columnIndex<=arrayLen(local.columns); local.columnIndex++) {
local.columnName = local.columns[local.columnIndex];
if(local.columnName != "" && (arguments.excludeColumns == "" || !listFindNoCase(arguments.excludeColumns, local.columnName))) {
local.response[local.rowIndex][local.columnName] = arguments.query[local.columnName][local.rowIndex];
}
}
}
return local.response;
}
</cfscript>
Please consider the following code:
Following tag inside header of my file
<script>
var chart;
var chartData = [{
ConnectionType: "First",
NumberPercentage: 1194,
{
ConnectionType: "Second",
NumberPercentage: 1882},
{
ConnectionType: "Third",
NumberPercentage: 1809},
{
ConnectionType: "Fourth",
NumberPercentage: 1322},
{
ConnectionType: "Fifth",
NumberPercentage: 1122},
{
ConnectionType: "Sixth",
NumberPercentage: 1114},
{
ConnectionType: "Seventh",
NumberPercentage: 984}
];
AmCharts.ready(function() {
// PIE CHART
chart = new AmCharts.AmPieChart();
// title of the chart
chart.addTitle("3D Donut Charts", 16);
chart.dataProvider = chartData;
chart.titleField = "ConnectionType";
chart.valueField = "NumberPercentage";
chart.sequencedAnimation = true;
chart.startEffect = "elastic";
chart.innerRadius = "30%";
chart.startDuration = 2;
chart.labelRadius = 15;
// the following two lines makes the chart 3D
chart.depth3D = 10;
chart.angle = 15;
// WRITE
chart.write("chartdiv");
});
</script>
Following tag inside body tag of my profile:
<div id="chartdiv" style="width: 100%; height: 362px;"></div>
I want to return the data from the following cfquery in my ColdFusion file. For the sake of simplicity I'm only mentioning cfquery for First connection. Rest cfqueries till seventh are same except the names.
<cfquery datasource = "XX.XX.X.XX" name="qCFCHART">
SELECT
Count(*) AS TOTAL_CONNECTION
, Sum(CASE WHEN 'FIRST' = EVENTS THEN 100 END) / Count(*) AS FIRST
, Sum(CASE WHEN 'SECOND' = EVENTS THEN 100 END) / Count(*) AS SECOND
, Sum(CASE WHEN 'THIRD' = EVENTS THEN 100 END) / Count(*) AS THIRD
, Sum(CASE WHEN 'FOURTH' = EVENTS THEN 100 END) / Count(*) AS FOURTH
, Sum(CASE WHEN 'FIFTH' = EVENTS THEN 100 END) / Count(*) AS FIFTH
, Sum(CASE WHEN 'SIXTH' = EVENTS THEN 100 END) / Count(*) AS SIXTH
, Sum(CASE WHEN 'SEVENTH' = EVENTS THEN 100 END) / Count(*) AS SEVENTH
FROM MyDatabase;
</cfquery>
Considering the code from above script:
ConnectionType: "First",
NumberPercentage: 1194,
I want to display the result returned by "FIRST" from the above query into my Pie Chart and writing cfdump or anything ColdFusion related doesn't work there.
For example:
ConnectionType: "First",
NumberPercentage: <cfdump var="#qCFCHART.FIRST#>",
The above throws an error and I see an obvious reason because I'm inside script tag and I'm wondering how to proceed? Any suggestions?
Here is my attempt after following some comments:
<cfoutput query="qCFCHART">
#currentrow#)
<cfloop index="col" list="#columnlist#">
#col#=#qCFCHART[col][currentRow]#
</cfloop>
<p/>
</cfoutput>
<cfset cols = getMetadata(qCFCHART)>
<cfdump var="#cols#">
You will need to loop over the query and create a data structure similar to what the chart is expecting - which appears to be an array of structures.
I am not going to give you the code to do this as it is a fairly simple operation, and one you could easily find information on if you choose to look for it.
You can then use serialzeJSON( data ) to get the JSON version of your data - which should have the same structure as chartData in your sample code.
What you need to do is output values from your server-side coldfusion query into your client-side javascript. e.g
<cfoutput>
var chartData = [{
ConnectionType: "First",
NumberPercentage: #qCFCHART.FIRST#},
{
ConnectionType: "Second",
NumberPercentage: #qCFCHART.Second#},
{
ConnectionType: "Third",
NumberPercentage: #qCFCHART.Third#},
{
ConnectionType: "Fourth",
NumberPercentage: #qCFCHART.Fourth#},
{
ConnectionType: "Fifth",
NumberPercentage: #qCFCHART.Fifth#},
{
ConnectionType: "Sixth",
NumberPercentage: #qCFCHART.Sixth#},
{
ConnectionType: "Seventh",
NumberPercentage: #qCFCHART.Seventh#}
];
</cfoutput>
The main reason your cfdump approach might not have worked is because you have a syntax error here:
<cfdump var="#qCFCHART.FIRST#>"
Should have been
<cfdump var="#qCFCHART.FIRST#">
But I'd strongly recommend against using cfdump; just output the value normally, there shouldn't be any need to 'dump' values into production code.
The simple fix to this question was that I needed to mention <cfoutput>#serializeJSON(qCFCHART.First)#</cfoutput> after Number Percentage field and it worked fine.
My JSON contains special characters like: new line, double quotes etc.
I am creating the JSON using Coldfusion server side script. But in case of special chars I get error due to wrongly formatted JSON. What should I do in such a case?
<cfoutput>
[
<cfset loopIndex=0>
<cfloop query="qEvents">
<cfif loopIndex NEQ 0>,</cfif>
<cfif is_allday EQ 1>
<cfset isallDayEvent = "true">
<cfelse>
<cfset isallDayEvent = "false">
</cfif>
{
"title": "#title#",
"start": "#DateFormat(start_date_time,'mm/dd/yyyy')# #TimeFormat(start_date_time,'hh:mm tt')#",
"end": "#DateFormat(end_date_time,'mm/dd/yyyy')# #TimeFormat(end_date_time,'hh:mm tt')#",
"allDay": #isallDayEvent#,
"eventID": "#event_id#",
"duration": "#duration#",
"note": "#note#",
"location": "#location#"
}
<cfset loopIndex=loopIndex+1>
</cfloop>
]
</cfoutput>
Rather than writing the JSON by hand, you should generate an array of structs and then use serializeJSON() to convert it to a valid JSON string:
<cfset thisArrayBecomesJSON = [] />
<cfloop query="qEvents">
<cfif is_allday EQ 1>
<cfset isAllDayEvent = "true" />
<cfelse>
<cfset isAllDayEvent = "false" />
</cfif>
<cfset thisEvent = {
'title' = title,
'start' = dateFormat( start_date_time, 'mm/dd/yyyy' ) & timeFormat( start_date_time, 'hh:mm tt' ),
'end' = dateFormat( end_date_time, 'mm/dd/yyyy' ) & timeFormat( end_date_time, 'hh:mm tt' ),
'allDay' = isAllDayEvent,
'eventID' = event_id,
'duration' = duration,
'note' = note,
'location' = location
} />
<cfset arrayAppend( thisArrayBecomesJSON, thisEvent ) />
</cfloop>
<cfset myJSON = serializeJSON( thisArrayBecomesJSON ) />
<cfoutput>#myJSON#</cfoutput>
This is untested, but I think it should work ok - there may be some syntax errors.
Wondering if anyone can assist
I am utilizing some code from RIAForge which integrates with the Last.fm api...
One of the methods outputs as a struct, but I would like to modify the code so it outputs as an array, am unsure of how to do this..
Currently the code is like this
<cfscript>
var args = StructNew();
var returnStruct = StructNew();
var results = "";
var i = 0;
args['playlistURL'] = arguments.playlistURL;
results = super.callMethod('playlist.fetch', args).playlist;
returnStruct['title'] = results[':title'];
returnStruct['annotation'] = results[':annotation'];
returnStruct['creator'] = results[':creator'];
returnStruct['date'] = results[':date'];
if(StructKeyExists(results, ':trackList') AND StructKeyExists(results[':trackList'], ':track')){
results = super.ensureArray(results[':trackList'][':track']);
returnStruct['tracks'] = QueryNew('album,creator,duration,identifier,image,info,title');
for(i=1; i LTE ArrayLen(results); i=i+1){
QueryAddRow(returnStruct.tracks);
QuerySetCell(returnStruct.tracks, 'album', results[i].album);
QuerySetCell(returnStruct.tracks, 'creator', results[i].creator);
QuerySetCell(returnStruct.tracks, 'duration', results[i].duration);
QuerySetCell(returnStruct.tracks, 'identifier', results[i].identifier);
QuerySetCell(returnStruct.tracks, 'image', results[i].image);
QuerySetCell(returnStruct.tracks, 'info', results[i].info);
QuerySetCell(returnStruct.tracks, 'title', results[i].title);
}
}
return returnStruct;
Am just wondering if there is a coldfusion method that allows me to convert the returnStruct into a query..
Many thanks
In CF 10 and Railo 4, you can use the QueryNew() function if you have an array of structs that you want to convert to a query.
Usage: QueryNew(columnList, columnTypeList, arrayOfStructs)
CFLIB.org is your friend
QueryToArrayOfStructures
You'll need to do it by hand by looping over your results and placing in an Array of Arrays. If, you want to convert your struct to a query there are functions at http://www.cflib.org that are ready to go.
var returnArray = []; /* or arrayNew(1) if not on Railo or CF9 */
/* ACF9 or Railo Style */
arrayAppend(returnArray, [results[':title'],results[':annotation'],results[':creator'],results[':date'] ]);
/* ACF8 and earlier */
arrayAppend( returnArray, arrayNew(1) ]);
arrayAppend( returnArray[ arrayLen(returnArray) ], results[':title'] ]);
arrayAppend( returnArray[ arrayLen(returnArray) ], results[':annotation'] ]);