5

The app: A JavaScript function listens for changes on form elements (input & select), and posts the data to a CFC method that assigns them to a Session struct. The struct is returned, making the form data usable for the life of the session. The app is adapted from code at Raymond Camden's Using a server, or session storage, to persist form values.

Issue: The original CFC code is written in CFScript. Because we're on ColdFusion 8, I get an error when the method is called. So, I translated the method into ColdFusion tag syntax and stopped getting that error. In Chrome's Dev Tools, I can see data passing to the CFC via the JSON object each time I enter something into a form element. So I know the JavaScript function is working. And even though I'm not getting any return errors, there are some behaviors that lead me to believe that my translation is incorrect. E.g., the dump of the session struct only displays the last input element entered, rather than all of them (as is the case in Ray's demo).

Here's the original CFScript version and then my tag translation. In addition to any comments about where my translation is wrong, I'd love to have an explanation of this line, <cfset s.name = [s[name]] />, particularly the [s[name]] construct, since I'm not able to articulate what's happening there. Thanks.

script syntax:

component {
    remote void function preserveSession(string awardData) {
        if(!isJSON(arguments.awardData)) return;
        arguments.awardData = deserializeJSON(arguments.awardData);

        //convert the array into a name based struct
        var s = {};
        for(var i=1; i<=arrayLen(arguments.awardData); i++) {
            var name = arguments.awardData[i].name;
            if(!structKeyExists(s, name)) {
                s[name] = arguments.awardData[i].value;    
            } else {
                //convert into an array
                if(!isArray(s[name])) {
                    s[name] = [s[name]];
                }
                arrayAppend(s[name], arguments.awardData[i].value);
            }    
        }
        session.awardFormData = s;    
    }
}

tag syntax:

<cfcomponent>
    <cffunction name="preserveSession" access="remote" returntype="void" output="no">

        <cfargument name="awardData" type="string" />

        <cfset var s = {} />

        <cfif NOT isJSON(arguments.awardData)>
            <cfreturn />
        </cfif>

        <cfset arguments.awardData = #deserializeJSON(arguments.awardData)# />

        <cfloop index="i" from="1" to="#arrayLen(arguments.awardData)#">
            <cfset name = #arguments.awardData[i].name# />

            <cfif NOT structKeyExists(s, name)>
                <cfset s.name = #arguments.awardData[i].value# />   
            <cfelse>
                <cfif NOT isArray(s.name) >
                    <cfset s.name = [s[name]] />
                </cfif>
                <cfset arrayAppend(s.name, arguments.awardData[i].value) />
            </cfif>
        </cfloop>

        <cfset session.awardFormData = s />

        <cfreturn />
    </cffunction>
</cfcomponent>
4

2 回答 2

5

首先,你不需要翻译所有这些。CF8 不支持 cfscript 中的组件/功能,但您最好按原样使用它:

<cfcomponent>
  <cffunction name="preserveSession" access="remote" returntype="void" output="no">
    <cfargument name="awardData" type="string" />
      <cfscript>
        var s = {};
        var name = '';
        var i = 0;
        if(!isJSON(arguments.awardData)) return false;
        arguments.awardData = deserializeJSON(arguments.awardData);
        for(i=1; i<=arrayLen(arguments.awardData); i++) {
          name = arguments.awardData[i].name;
          if(!structKeyExists(s, name)) {
            s[name] = arguments.awardData[i].value;
          } else {
            if(!isArray(s[name])) {
              s[name] = [s[name]];
            }
            arrayAppend(s[name], arguments.awardData[i].value);
          }
        }
        session.awardFormData = s;
        return true;
    </cfscript>
  </cffunction>
</cfcomponent>

试着像这样简单地重新包装胆量,而不是重写,看看你是否能走得更远。

对符号进行一般性解释:存储在中的值的键s[name]地址结构;这有时称为数组表示法。它相当于名称已知位置的点表示法。要通过变量名动态地寻址结构,最简单的方法是通过数组表示法来做到这一点。snames.theValueStoredInName

嵌套集也是如此:该行s[name] = [s[name]]正在设置一个键,其值与存储name的值相同,并与存储在命名键中的值相同s[name]。通过将该集合包装在 中[],它是一种数组。

这将有助于澄清这里具体发生了什么:

如果尚未将具有该名称键的内容分配为结构,则将其存储为结构(简单名称键值)。如果有,那么 name-key 值中的任何内容都将转换为具有该 name-key 的数组。然后,如果它是第二项的连续传递(它将是,if!只是检查此数组转换是否已经发生至少一次),那么第二项将附加到具有键的数组一样的名字。

就个人而言,为了简单起见,我总是直接设置为数组。然后你总是知道如何处理存储中的值。

于 2013-06-05T19:19:54.060 回答
2

<cfset s.name = ... />

您需要动态访问键名。name上面的代码每次都使用相同的静态键(即)。因此,每次循环时,您最终都会覆盖先前的值。这就是为什么你最终只有一个值 - 最后一个。

 <!--- this creates a dynamic key named "apple" (correct) --->
 <cfset name = "apple" />
 <cfset s[name] = "..." />

 <!--- this creates a key literally named "name" (wrong) --->
 <cfset name = "apple" />
 <cfset s.name = "..." />

要修复它,在您使用的任何地方s.name,将其替换为s[name]. 此外,不要忘记将var所有函数局部变量的范围。

更新:

williambq 的回应也提出了一个很好的观点。您不必将其全部转换为 cfml。将大部分内容包装在cfscript标签中更简单。

于 2013-06-05T19:13:32.883 回答