Working with Form Arrays in ColdFusion? - html

I have no idea how to handle this in ColdFusion 9, I have a form being submitted (POST) with element checkboxes, called items[].
When I do a <cfdump var="#form#" /> no-problem, I get all the items shown with the proper names like items[] eg:
struct
ITEMS[] 13,14
FIELDNAMES ITEMS[]
however doing a <cfdump var="#form.items[]#" /> results in an error. How do I access the CF9 field values? Somehow loop through it?
I cannot seem to do anything with the array to get the id's out of it? Thoughts? I'm kind of stumped and ColdFusion isn't the easiest language to find examples / references on the net. ;)
Is there a correct way to deal with this? I need to get the ID's out of there so I can reference what lines were checked in the form, so I can follow up with an action.
Thanks!

There's no Form Array’s in ColdFusion. Having '[]' at the end doesn't make it an array. You can access the checkbox values from form scope like this:
FORM["ITEMS[]"]
Dot notation doesn't work 'cause of the '[]'. See: http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec22c24-7fb2.html
Values from checkboxes are just comma separated values, which is a List in ColdFusion
To loop through it, use cfloop list=:
<cfoutput>
<cfloop index="i" list="#FORM['ITEMS[]']#">
#i#
</cfloop>
</cfoutput>
To convert a list to array, use ListToArray(). There are list functions like listGetAt(), but if you're doing lots of random access, it'd be smarter to convert the list into an array first.
Thoughts, I'm kindof stumped and
coldfusion isn't the easiest language
to find examples / references on the
net ;)
http://help.adobe.com/en_US/ColdFusion/9.0/Developing/index.html
http://learncf.com/tutorials
http://www.easycfm.com/
http://www.carehart.org/ugtv/

I can highly recommend Brian Kotek's "Form Utils" for cases such as this: http://www.briankotek.com/blog/index.cfm/2007/9/4/Implicit-Creation-of-Arrays-and-Structures-from-Form-Fields
I use this in every app I build, because working with arrays and structs on the form submission side is much more preferable to working with lists, imo.

See also the second answer here. It describes how to retrieve values from a field with multiple instances on a form as an array. I have to say though, I've been working in CFML for many years, and I've yet to do this myself, or see it done in any app I've worked on. I think that's just because avoiding commas is very much simpler, but if you can't or don't want to work around it that way, it is possible.

Also, note that in an ajax world, if you json encode the entire body of a post request, rather than individual form fields, it can be any arbitrary data structure, retrievable easily on the server. The snippet below shows how to get to it from ColdFusion. I'm not certain about other languages, but it's almost certainly possible.
To send a post like that using jQuery, JSON.stringify your data before passing it to jQuery, as noted here and here.
If you're building your own ajax request, the punchline would be:
xhr.send(JSON.stringify(data));
To access that data on the server side, this ColdFusion example looks first for that kind json-encoded post body, then a post with json data in the form field 'input', then in a url field with that same name. In all cases, the resulting data gets deserialized and assigned to the local var 'input', which you can then put in request scope, 'rc', or whatever your code expects.
if (Find('application/json', cgi.content_type))
{
input = ToString(GetHttpRequestData().content);
if (IsJSON(input))
input = DeserializeJSON(input);
}
else if (StructKeyExists(form, 'input') and IsJSON(form.input))
input = DeserializeJSON(form.input);
else if (StructKeyExists(url, 'input') and IsJSON(url.input))
input = DeserializeJSON(url.input);

With you list that are Id's it works fine, but if you have an array with comma's in then you're stuck.
In that case you can use the Java method getParameterValues.
<cfdump var="#getPageContext().getRequest().getParameterValues('ITEMS')#">
This will give you an standard CF array which you can use.

For ColdFusion 10+, if you use the sameformfieldsasarray setting in your Application.cfc like this:
component {
this.name = "testingzone2c";
this.sameformfieldsasarray=true;
}
You will get an actual array of form fields with the same name.
ColdFusion 10 Missing Feature - Form Fields and Arrays

I suggest that you remove the "[]" from the name since it disallows dot notation as mentioned in another answer.. When more than one form element contains the same name attribute, the browser will concatenate all of the values into a comma delimited string when submitting the form. Fortunately, ColdFusion has many functions which treat a delimited string as a list. You can use <cfloop> along with these functions to consume the list.

Related

How to read a field that is json or a xml object in Crystal Report

I have a field that is json object.
SELECT json_array (json_object ('a' value 1)) j FROM DUAL.
[{"a":1}]
Crystal Report considers that it is a varchar2(4000) (right Click on the field and than click onfield type)
In this example, I would like to give orders like that:
count({command.j}) --How many line has my tab of json. 1
and
{command.j}[1][a] --value of the line 1 for the field a
Is it possible and how do I do that?
A solution that works with xml suits me too.
updated
I've tried ExtractString({YourJsonString}, "[{""a"":", "}]").
But it doesn't work if the json has several fields or array several lines
[{"a":1,"b":2}] -> 1,"b":2},{"a":11,"b":22
[{"a":11,"b":22}] -> 1,"b":2},{"a":11,"b":22
Furthermore. I've said that I don't have nested json. But I would like a function that works in all cases. I'm search for a function that's meant to handle json
If you need to use a standard JSON path to specify the target elements, afaik, the only reasonable approach is to use a Crystal UFL (User Function Library).
You can implement your own UFL or use a 3rd-party Crystal Reports UFLs. Ken Hamady maintains a list of 3rd-party UFLs here.
Here is an example of using a Crystal Reports UFL to return JSON content by specifying a path:
Please provide a sample json text and the expected results for it.
Use Split({YourJsonString}, "][") to get an array.
The count is simply the size of the array.
To get the value for "a", use:
ExtractString({YourJsonString}, "[{""a"":", "}]")

ColdFusion Query Page returning JSON

So I am trying to repurpose an old Coldfusion page for an internal DBA tool to track long running queries.
The page currently does a query as a <CFQUERY name="GetLongRunners"> and then displays the data in a table format:
<table>
<tr>
<td>#GetLongRunners.spid#</td>
<td>#GetLongRunners.Database#</td>
</tr>
</table>
etc, etc
My goal is to strip out all of the display stuff, and be able to simply post to this page, and then receive JSON back with this same data. I played around with:
jsonData = SerializeJSON(#GetLongRunners#)
along with trying to be more specific with #GetLongRunners.database# and it does not seem to be working. The page shows 'jsonData = SerializeJSON(' and I get an error:
Complex object types cannot be converted to simple values.
I'm very new to ColdFusion, and am trying to encapsulate this functionality as much as I can, so I really only have to worry about posting to this page, and then I can get the raw JSON to work with in the front end.
All examples I found, built the queries in a very different way, and it seems to be outside my scope to do it this way.
I am picturing a simple way to serialize the query output as json and send it back as a JSON object. Either that, or build an array by looping through the results of the query, and then serializing that.
Any ideas?
Thanks!
If you are on CF7, try the JSONUtil.cfc. Just download the CFC and install it somewhere under the web root. Then it is ready to use.
Inside your .CFM script, run the query, create an instance of the JSONUtil, and invoke the serializeJSON() method. That is it.
<cfsetting enablecfoutputonly="true">
<cfquery name="GetLongRunners">.... your query here .... </cfquery>
<cfset util = createObject("component", "path.to.JSONUtil")>
<cfcontent type="application/json" reset="true">
<cfoutput>#util.serializeJSON(GetLongRunners)#</cfoutput>
As Henry noted, extra white space can be problem when using .cfm files in this way. Be sure to include the cfsetting at the very top of your script. It will suppress output from everything except content wrapped in <cfoutput> tags.
Truthfully I would use a CFC for this instead, but one thing at a time. If you are interested, this thread has an example of using a remote function as well as converting a query object into a more friendly format ie array of structures.
<cfsetting enablecfoutputonly="true">
<!--- logic/calculation --->
<cfset jsonData = SerializeJSON( GetLongRunners )>
<!--- lastly, output the result --->
<cfoutput>#jsonData#</cfoutput>

How do I pass data between tvml views?

I need to pass data between views in my client-server app. For simple string value, I can put them as attributes on the target element and read the value when the select event is triggered on it. From there, I can pass this string value onto the next document pretty easily.
But the problem comes with much more complex data that's in JSON format. I tried doing JSON.stringify(myData) and putting this value in an attribute. But the compiler doesn't like the { in this attribute value.
I could probably try escaping all the different characters that the compiler has problems with. But I don't think that's a good idea.
Is there any way of implementing jQuery's .data() functionality in TVML and TVJS ? Or is there any other way that makes sending data between views a possibility ?
You can pass your data as URL parameters. Then in the new view, get them using Javascript.
EDIT: And I see in the comment above you came to a similar conclusion.
You could keep your data in a semi-global associative array. Store the key in an attribute on the element and use that to get your data structure.
Ex:
var globalData;
function onSelect(e){
var id=e.target.getAttribute("id");
var specificData=globalData[id];
}

Sort BC WebApp on front end using a custom field

I have created a BC WebApp using the BC Open Platform API's for the back end and everything appears to work fine including rendering the list of items in a sort order of one of my custom fields.
Here is an example of what works on the back end.
var items = new BCAPI.Models.WebApp.ItemCollection(WEBAPP_NAME);
items.fetch({
order: "MyCustomField",
skip: 0,
limit: 1000,
success: onWebpAppListFetch,
error: onAPIError
});
How do I render this list on the front end sorted by one of my custom fields? Here is an example of what I am trying to use on the front end, but it does not order or sort this way.
{module_webapps order="MyCustomField" render="collection" template="/_System/apps/cms-sports-club-manager/club-rooms/layouts/club_rooms_collection.tpl" id="cms-club-roomsx" filter="all"}
Is there something that I am overlooking, or do I need to approach this in my own manual way? Perhaps I could render the list into an array, sort the array and then iterate through that to render the front end listing? The template file uses Liquid to iterate through the collection and render the HTML. Can I define an array variable, fill the array, sort the array and iterate through the array again in that same template file?
Another possibility perhaps is to output all webapp items into a JSON file each time a user creates/edits an item (from the back end), and then use the {module_json} feature on the front end to read that JSON file which "should" allow me to sort it.
Any advice on what to do (as well as what NOT to do) would be appreciated.
I have found one possible answer, but I am not sure it is the best way to do this.
I have implemented a script which performs the following steps:
Create an array holding all items (unsorted at this point)
Sort the array using any custom field
Iterate through the sorted array and document.write() each one
I have tested this a fair bit and it seems to do exactly what I want, however I have not marked this as the correct answer just yet as I would still like to find a "better" way than needing to resort to the above manual work.

Insert a Coldfusion struct into a database

If I wanted to save a contact form submission to the database, how can I insert the form scope in as the submission? It's been some time since I used Coldfusion.
The contact forms vary depending on what part of the site it was submitted from, so it needs to scale and handle a form with 5 fields or one with 10 fields. I just want to store the data in a blob table.
Most space efficient way and least complicated to turn back into original shape is using serializeJSON. After that, you can use something like key:value|key:value, or XML representation of your struct.
Cfwddx is also an alternative.
I don't know that there is a way to store a native structure into a database, but have you thought about using JSON to represent your object as key-pair values and then parsing it into a native structure after retrieving it from the database?
There are tags/functions out there that will help you with the encoding and decoding into JSON:
cfJSON Tag
CF8 Serialize JSON
CF8 Deserialize JSON
If you can't normalize the form fields into proper table(s), you can try storing them:
in XML (SQL Server supports XML pretty well), or
in JSON (in a plain varchar field), or
ObjectLoad() & ObjectSave() (CF9 only) to store as blob.
IIRC there are ways to get object load/save functionality in pre-CF9 by tapping into Java. http://www.riaforge.org/ or http://cflib.org/ might have it.