【问题标题】:JSON returned from remote CFC function is out of order从远程 CFC 函数返回的 JSON 乱序
【发布时间】:2011-11-26 05:02:40
【问题描述】:

我有一个返回结构的远程 CFC。它使用 cfajaxproxy 调用。我希望返回的 JSON 是有序的,即首先进入结构,然后进入 JSON 对象。但是,返回的 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);

这是发送到 post 请求中的函数的数据(上面的变量)。

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

现在这将焦点放在表单的第二个字段,描述,而不是项目字段。

【问题讨论】:

标签: jquery json coldfusion cfc


【解决方案1】:

除非您手动构建字符串以返回该数据,否则您无法(轻松)控制返回的 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 键。将它们完全分解成一个单独的实体,这样您就可以更轻松地在客户端循环遍历它们。

【讨论】:

  • 如果遇到任何障碍,请告诉我。我直接在答案中输入了代码,并没有实际运行它来测试它。但是,一切都应该顺利进行。
  • 我发现你的代码有一个问题。 tempError 结构仅被添加到数组中一次并不断被覆盖,因此只有最后一个错误出现在错误数组中。在每个 cfif 块中移动 tempError = StructNew() 可以解决此问题。
  • 知道了,我已经用 Duplicate 函数纠正了这个问题,所以你不必每次都重新初始化变量。
【解决方案2】:

ColdFusion 结构的键永远不会以任何特定顺序存储。但是,我 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>

编辑: Dan 的解决方案(数组而不是结构)可能会容易得多。

【讨论】:

  • 如果我只通过 ajax 调用使用远程验证功能,我可能会采用 Dan 的方法并在数组中返回错误。但是,如果他们禁用了 JS,我也会在服务器上调用该函数。在我的错误显示代码中返回结构而不是数组中的错误效果更好。使用 LinkedHashMap 解决了这个问题;返回的 JSON 与添加项目的顺序相同。
【解决方案3】:

struct 在 CFML 中没有排序(它只是一个类似 Hashmap 的集合)。

如果你想要有序结构,使用

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

【讨论】:

    【解决方案4】:

    如果您想让某些东西保持有序,最简单的方法是使用数组而不是结构。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-26
      • 1970-01-01
      • 2017-03-12
      • 2019-06-02
      相关资源
      最近更新 更多