2011-09-27 23 views
6

我有一個遠程CFC返回一個結構。它被稱爲使用cfajaxproxy。我希望返回的JSON按順序排列,即首先將結構放入JSON對象中。但是,返回的JSON按照混合順序排列。從遠程CFC功能返回的JSON出現故障

這裏是遠程功能。

<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> 

這是我設置爲我的表單頁面的頂部cfajaxproxy。

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

下面是在我的表單的onSubmit處理程序中對遠程函數的調用。

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

下面是發送到發佈請求中的函數的數據(上面的變量)。

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

這是從函數返回的JSON響應。

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

我希望響應與創建結構的順序相同,看起來像這樣。

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

當我遍歷我可以將焦點設置到第一種形式場與它的錯誤的響應的方式。

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; 
     } 
    } 
}); 

現在這個地方的焦點集中在form,description的第二個字段中,而不是在項目字段中。

+0

可能的重複http://stackoverflow.com/questions/4515676/keep-the-order-of-the-json-keys-during-json-conversion-to-csv –

回答

7

ColdFusion結構的鍵從不以任何特定順序存儲。但是,I found one post顯示瞭如何創建Java LinkedHashMap(它是CF Struct下面的java)以按特定順序存儲和檢索密鑰。

<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>

編輯:丹的解決方案(數組,而不是結構)可能會容易得多。

+0

如果我只是通過ajax調用來使用遠程驗證功能,我可能會用Dan的方法去解決,並將錯誤返回給數組。不過,如果他們禁用JS,我也會在服務器上調用該函數。在結構而不是數組中返回錯誤可以更好地處理我的錯誤顯示代碼。使用LinkedHashMap解決了這個問題。返回的JSON與項目添加順序相同。 – Brandon

5

除非手動構建字符串以返回該數據,否則無法(輕鬆地)控制返回的JSON結構數據的順序。如果您必須依賴訂單,那麼您需要將錯誤返回給數組而不是結構。你甚至可以返回一個錯誤結構數組,CF將保持正確的數組順序。

我會回到你的數據像這樣:

<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> 

這會給你錯誤的一個單獨的數組遍歷,而不是處理你的基地message,並在同一時間,你的錯誤areErrors鍵。把它們分解成一個獨立的實體,你就可以在客戶端更容易地循環它們。

+0

這聽起來像是正確的做法。我會試試看。 – Brandon

+0

讓我知道你是否遇到任何困難。我直接在答案中輸入了代碼,並沒有真正運行它來測試它。然而,一切都應該很好去。 –

+0

我的代碼有一個問題。 tempError結構只會被添加到數組中,並且一直被覆蓋,因此只有最後一個錯誤出現在錯誤數組中。在每個cfif塊的內部移動tempError = StructNew()修復了這個問題。 – Brandon

3

struct沒有在CFML中排序(它只是一個類似Hashmap的集合)。

如果您想訂購結構,如果你想要的東西留下來,以便使用數組,而不是一個結構的使用

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

最簡單的方法。