JSON returned with remote CFC function not working

I have a remote CFC that returns a structure. It is called using cfajaxproxy. I want JSON to return in order, that is, first in the structure first in the JSON object. However, the returned JSON is in mixed order.

Here is the remote function.

<cfcomponent displayname="validation" hint=""> <cffunction name="validateForm" displayname="validateForm" hint="" access="remote" verifyClient="yes" returntype="struct"> <cfargument name="formVals" type="struct" required="yes"> <cfset errors = StructNew()> <cfif formVals.project neq "project"> <cfset errors["project"] = "Invalid project name." /> </cfif> <cfif Len(formVals.description) eq 0> <cfset errors["description"] = "Please enter a description." /> </cfif> <cfif StructIsEmpty(errors)> <cfset errors["message"]["type"] = "success"> <cfset errors["message"]["text"] = "Client and server-side validation passed successfully."> <cfset errors["areErrors"] = false> <cfelse> <cfset errors["message"]["type"] = "validation"> <cfset errors["message"]["text"] = "Please fix the errors, and resubmit."> <cfset errors["areErrors"] = true> </cfif> <cfreturn errors /> </cffunction> </cfcomponent> 

This is cfajaxproxy, which I installed at the top of my form page.

 <cfajaxproxy cfc="validation" jsclassname="validation"> 

Here's the call made to the remote function in the onSubmit handler of my form.

 var v = new validation(); v.setHTTPMethod("POST"); var errors = v.validateForm(o); 

Here is the data (o variable above) that the functions are sent to the post request.

 {"formVals":{"project":"","description":""}} 

Here the JSON response is returned from the function.

 {"message":{"text":"Please fix the errors, and resubmit.","type":"validation"},"description":"Please enter a description.","project":"Invalid project name.","areErrors":true} 

I want the answer to be in the same order in which the structure was created that would look like this.

 {"project":"Invalid project name.","description":"Please enter a description.","message":{"text":"Please fix the errors, and resubmit.","type":"validation"},"areErrors":true} 

That way, when I repeat the answer, I can set the focus in the first form field with an error in it.

 var focusSet = false; $.each(errors, function(key, val){ //alert(key + ': ' + val); if(key != 'message' && key != 'areErrors') { var fi = $('#' + key).parents('.formItem').filter(':first'); fi.addClass("inError"); fi.find('.err').filter(':first').html(val); if(!focusSet) { $('#' + key).focus(); focusSet = true; } } }); 

Currently, these places are focused in the second field of the form, description, and not in the project field.

+6
source share
4 answers

The keys to the ColdFusion structure are never stored in any particular order. However, I found one post that shows how you can create java LinkedHashMap (which is java under CF Struct) to store and retrieve keys in a specific order.

 <cfset pets = CreateObject("java", "java.util.LinkedHashMap").init()> <cfscript> pets["Cat Name"] = "Leo"; pets["Dog Name"] = "Meatball"; pets["Fish Name"] = "Lil Fish"; pets["Bird Name"] = "PePe"; pets["Snake Name"] = "Sizzle"; </cfscript> <cfloop collection="#pets#" item="key" > <cfoutput> #key#: #pets[key]#<br/> </cfoutput> </cfloop> 

EDIT: Dan's solution (an array instead of a structure) is likely to be much simpler.

+7
source

You cannot (easily) control the order of the returned data in the JSON structure unless you manually create a row to return that data. If you must rely on ordering, you need to return your errors to an array instead of a structure. You can even return an array of error structures, and CF will maintain the correct order of the array.

I would return your data like this:

 <cfcomponent displayname="validation" hint=""> <cffunction name="validateForm" displayname="validateForm" hint="" access="remote" verifyClient="yes" returntype="struct"> <cfargument name="formVals" type="struct" required="yes"> <cfset var retVal = StructNew() /> <cfset var tempError = StructNew() /> <cfset retVal.errors = ArrayNew(1) /> <cfif formVals.project neq "project"> <cfset tempError["key"] = "project" /> <cfset tempError["message"] = "Invalid project name." /> <cfset ArrayAppend(retVal.errors, Duplicate(tempError)) /> </cfif> <cfif Len(formVals.description) eq 0> <cfset tempError["key"] = "description" /> <cfset tempError["message"] = "Please enter a description." /> <cfset ArrayAppend(retVal.errors, Duplicate(tempError)) /> </cfif> <cfif ArrayIsEmpty(retVal.Errors)> <cfset retVal["message"]["type"] = "success" /> <cfset retVal["message"]["text"] = "Client and server-side validation passed successfully."> <cfset retVal["areErrors"] = false> <cfelse> <cfset retVal["message"]["type"] = "validation"> <cfset retVal["message"]["text"] = "Please fix the errors, and resubmit."> <cfset retVal["areErrors"] = true> </cfif> <cfreturn retVal /> </cffunction> </cfcomponent> 

This will give you a separate array of errors to iterate over, instead of accessing your base message and areErrors keys at the same time as your errors. Divide them into a separate object as a whole, and it will be easier for you to scroll them on the client side.

+5
source

struct is not ordered in CFML (it's just a collection similar to a Hashmap).

If you want an ordered structure, use

 struct function orderedStructNew() { return createObject("java","java.util.LinkedHashMap").init(); } 
+3
source

The easiest way, if you want something to stay in order, uses Array instead of structure.

+2
source

Source: https://habr.com/ru/post/898158/


All Articles