I have an array called device, which looks like this (simplified):
label : "Device 1",
exhibits : [{
item : 1,
desc : "This is a sample"
},{
item : 2,
desc : "This is another sample"
},{
item : 3,
desc : "This is a third"
}]
I'm trying to print exhibits neatly for a PDF, so I'm thinking comma-deliniated like this:
1, 2, 3
This is my code:
<cfloop array="#device.exhibits#" index="exhibit">
#exhibit.item#
</cfloop>
But I get this:
123
Yes, I could manually figure out if there should be commas or not, but is there a better way to do this?
Since you're using CF11+, you can use the ArrayMap function with an ArrayList to turn the array into a list.
exhibits.map( function(i) { return i.item ; } ).toList() ;
With your example array, it gives you "1,2,3".
In another of my answers, I stepped through handling empty elements. Since this is an array of structs, I don't know if this would be a problem. How are you getting this data for your exhibits array?
EDIT:
exhibits.map( function(i) { return i.item ; } )
.filter( function(j) { return len(j) ; } )
.toList() ;
will return the list with empty elements removed.
EDIT 2:
Per the question by #TravisHeeter, if you prefer lambda expressions or arrow functions, you can use them in Lucee 5.
exhibits.map( (i) => i.item ).filter( (j) => len(j) ).toList()
https://trycf.com/gist/907a68127ddb704611b191d494aa94ce/lucee5?theme=monokai
The usual approach is to extract the data first:
<!--- extract the itemNumber of every exhibit --->
<cfset itemNumberList = []>
<cfloop array="#device.exhibits#" index="exhibit">
<cfset itemNumberList.add(exhibit.itemNumber)>
</cfloop>
And then we transform the extracted data to a comma-separated list (string):
<cfset itemNumberList = arrayToList(itemNumberList, ", ")>
<!--- 1, 2, 3 --->
<cfoutput>#itemNumberList#</cfoutput>
Array-mapping (see Shawn's answer) is a more fancy (readable?) way.
I'm trying to use ColdFusion's SerializeJSON() to return JSON data.
So far I have done this:
<cfset rows = [] />
<cfloop query="rsProducts">
<!--- Create a row struct. --->
<cfset row = {} />
<!--- Add each column to our struct. --->
<cfloop
index="column"
list="#rsProducts.columnList#"
delimiters=",">
<cfset row[ column ] = rsProducts[ column ][ rsProducts.currentRow ] />
</cfloop>
<!--- Append the row struct to the row array. --->
<cfset arrayAppend( rows, row ) />
</cfloop>
<cfreturn SerializeJSON(rows, true)>
This works fine and produces JSON like this:
[Object {PRICE: 89.99, PRODUCTSTATUS: 1, COUNTRY: US}, Object {PRICE: 110.50, PRODUCTSTATUS: 4, COUNTRY: UK}, Object {PRICE: 41.20, PRODUCTSTATUS: 1, COUNTRY: IN}]
However instead of a label of "Object" for each item, I'd like it to be "ProductItem" instead. It just makes it easier for me to deal with in jQuery later on.
How could I have it so it labels each object in JSON as "ProductItem"?
You can loop over the data in this manner easily.
.success(function(data) {
var ProductItem = JSON.parse(data);
$.each(ProductItem,function(key,value){
console.log(value.PRICE +" "+ value.PRODUCTSTATUS + " " + value.COUNTRY);
});
I have a JSON variable output from a jQuery application as so:
[{"id":1},
{"id":197,"children":[{"id":198},{"id":199},{"id":200}]},
{"id":2,"children":[{"id":3},{"id":4},{"id":143},{"id":6},{"id":5},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12}]},
{"id":15,"children":[{"id":17},{"id":190},{"id":191},{"id":131},{"id":16},{"id":142},{"id":124}]},
{"id":149,"children":[{"id":150},{"id":160},{"id":161},{"id":184}]},
{"id":20,"children":[{"id":132},{"id":127},{"id":152},{"id":107},{"id":108},{"id":109},{"id":110},{"id":125},{"id":128},{"id":130},{"id":129},{"id":112}]},
{"id":162,"children":[{"id":163},{"id":164},{"id":165},{"id":166},{"id":186},{"id":187}]},
{"id":167,"children":[{"id":173},{"id":168},{"id":170},{"id":169},{"id":192},{"id":194}]},
{"id":174,"children":[{"id":176},{"id":175},{"id":188}]},
{"id":153,"children":[{"id":178},{"id":179},{"id":195},{"id":154},{"id":157}]},
{"id":180,"children":[{"id":181},{"id":182},{"id":183},{"id":189}]},
{"id":122},
{"id":21},
{"id":13},
{"id":92},
{"id":22},
{"id":113},
{"id":114}]
I need to convert this variable to a struct and then loop the struct by the first id parameter to find the children for each id (if there is one). I have tried to convert it as a structure like so but I am getting an error:
<cfset jsonarray = deserializeJson(output)>
<cfloop collection="#jsonarray#" index="id">
<cfdump var="#jsonarray[id]#">
</cfloop>
It does not recognize the variable as a structure:
Invalid collection [{id={1}}, {children={[{id={198}}, {id={199}}, {id={200}}]},id={197}}, {children={[{id={3}}, {id={143}}, {id={4}}, {id={6}}, {id={5}}, {id={7}}, {id={8}}, {id={9}}, {id={10}}, {id={11}}, {id={12}}]},id={2}}, {children={[{id={17}}, {id={190}}, {id={191}}, {id={131}}, {id={16}}, {id={142}}, {id={124}}]},id={15}}, {children={[{id={150}}, {id={160}}, {id={161}}, {id={184}}]},id={149}}, {children={[{id={132}}, {id={127}}, {id={152}}, {id={107}}, {id={108}}, {id={109}}, {id={110}}, {id={125}}, {id={128}}, {id={130}}, {id={129}}, {id={112}}]},id={20}}, {children={[{id={163}}, {id={164}}, {id={165}}, {id={166}}, {id={186}}, {id={187}}]},id={162}}, {children={[{id={173}}, {id={168}}, {id={170}}, {id={169}}, {id={192}}, {id={194}}]},id={167}}, {children={[{id={176}}, {id={175}}, {id={188}}]},id={174}}, {children={[{id={178}}, {id={179}}, {id={195}}, {id={154}}, {id={157}}]},id={153}}, {children={[{id={181}}, {id={182}}, {id={183}}, {id={189}}]},id={180}}, {id={122}}, {id={21}}, {id={13}}, {id={92}}, {id={22}}, {id={113.... Must be a valid structure or COM object.
In JSON, the [] denotes an array and {} a structure (or object). So your input is actually an array of structures. You need to use an array loop, not a collection loop:
<cfset arrayOfStructs = deserializeJson(output)>
<cfloop array="#arrayOfStructs#" index="parent">
<cfset parentID = parent.id />
...
</cfloop>
children is also an array of structures. Inside the outer loop, check for the existence of that key. If found, loop through the child array and do something with each of the id's:
<cfif structKeyExists(parent, "children")>
<cfloop array="#parent.children#" index="child">
...
</cfloop>
</cfif>
A tidy cfscript version. :)
<cfscript>
structObj = deserializeJson(jsonString);
for(i = 1; i LTE ArrayLen(structObj); i++){
WriteOutput("parent id : " & structObj[i].id & "<br>");
if(StructKeyExists(structObj[i], "children")){
for(j = 1; j LTE ArrayLen(structObj[i].children); j++){
WriteOutput(" -children id : " & structObj[i].children[j].id & "<br>");
}
}
}
</cfscript>
I created an Angular 1.4 ColdFusion 9 JSON Normalizer here
var myURL = 'myCfc.cfc?method=getItemsFromDb';
var app = angular.module('angularOutput',[]);
app.controller("sectionController", function($scope, $http) {
$http.get(myURL).
success(function(data, status, headers, config) {
var log = [];
var output = '';
angular.forEach(data.DATA, function(value, key) {
this.push(output +='{"value": ');
this.push(output += '"'+value[0]+'"');
this.push(output +=',"text":');
this.push(output += '"'+value[1]+'"');
this.push(output +='}');
this.push(output +=',');
}, log);
output = output.replace(/,\s*$/, "");/*had to remove the final comma */
output = '['+output+']'; /*had to add the [] to corectally form the output*/
$scope.sections = angular.fromJson(output);
}).
error(function(data, status, headers, config) {
console.log(data);
});
});
So I'm working on a pie chart using HighSlide and ColdFusion.
To make this simple, for the data it expects a string like this:
data: [{name: 'Jane',y: 13}, {name: 'John',y: 23}, {name: 'Joe',y: 19}]
What i've done to accomplish this is to loop through my query results and create a string like this:
<cfloop query="getAreaCounts">
<cfset areaList = listAppend(areaList, "{name: '#name#',y: #y#}")>
</cfloop>
I know there has to be an easier/smarter way right? Since this is JSON data, i figured I could just do this:
<cfoutput>#SerializeJSON(getAreaCounts)#</cfoutput>
But that returns a JSON string like this which highcharts won't process:
{"COLUMNS":["Y","NAME"],"DATA":[[8,"Area1"],[7,"Area2"],[1,"Area3"],[1,"Area4"]]}
Any help pointing me in the right direction would be great. Do I need to dig deeper into a JSON - howto?
You're going to want to convert the query to an array of structs and then run serializeJSON() on that array.
Below is a method that I use pretty frequently when working with a lot of queries and JSON. I think that I got it from Ben Nadel's site and then converted it to cfscript.. I'll try to track down the blog post after I post this answer.
public array function queryToArray( required query qry ) {
var columns = arguments.qry.getColumnNames();
var ofTheJedi = [];
for( var i = 1; i LTE qry.recordCount; i++ ) {
var obj = {};
for( var k = 1; k LTE arrayLen( columns ); k++ ) {
structInsert( obj, columns[ k ], arguments.qry[ columns[ k ] ][ i ] );
}
arrayAppend( ofTheJedi, obj );
}
return ofTheJedi;
}
So, in your case you would do something like this:
<cfset myJSON = queryToArray( getAreaCounts ) />
<cfoutput>#serializeJSON( myJSON )#</cfoutput>
EDIT: Here's Ben's blog post that inspired the method above: http://www.bennadel.com/blog/124-Ask-Ben-Converting-a-Query-to-an-Array.htm
You need something like this (untested but you get the idea)
<cfscript>
data = [{name='Jane',y=13],{name='John',y=23},{name='Joe',y=19}];
</cfscript>
<cfoutput>#serializeJson(data)#</cfoutput>
You need to create a Coldfusion array of strucutres (each with "name" and "y" as members).. then serialize it. What you are serializeing above is the query object. By your code it looks like you meant to serialze the "arealist" variable - but that var would probably not come out correct either because it is not an array of structures - it is a list of strings.