0

If there is a better way to go about this (which is quite likely), please let me know how to go about it.

I'm working on some code that is supposed to dynamically set the form variables as regular variables so that we can be lazy and not have to refer to the variable with form.somevariable name.

That part works perfectly. Until I start testing for URL conflicts in which a URL variable has the same name. For instance. . .

I have a form that passes two variables; FirstName and LastName. If I hit the page, the form shows up, I input a first and last name and click submit. The code works perfectly.

However, if I have URL variables with the same names, the code reports the url variable values instead of the form values.

Some sample values;

url.FirstName = Joe

url.LastName = Black

form.FirstName = Steve

form.LastName = White

My code that exposes the form variable will correctly find the form field names, but then when I 'evaluate' the value of the given form field, it will return the value of the URL variable of the same name rather than the form variable.

What I am really wanting (as I described briefly up above) is to have code that automatically converts client, URL and Form variables into 'regular variables' so that you don't have to write lots of extra code grabbing them later on. Frameworks like CFWHEELS and ColdBox do this by default, but at the company I work out, we aren't using any of them. I need it to expose the URL variables, but give presidence to form variables if they have the same name, because they are likely to be intended to do an update or such.

The code follows Feel free to ignore the code for the URL and client variables if you wish as they don't directly affect how the form code works, I have tested with them commented out and I get the same result. I provided all of it to give a more complete idea of what I have been toying with so far. Please note that I don't normally use 'evaluate'. There is probably a better way to go, but I don't know what it is.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++

First Name Last Name


URL variables:

<cfloop index="i" list="#paramsurl#">

    <cfset myDynVar = Evaluate(i)>



    <!--- Let's output the dynamically created variable as a test --->

    #i# = #myDynVar#<br />

</cfloop>

<cfoutput>

    <b>Field Names:</b> #Form.FieldNames#

    <p>

        <b>Field Values:</b><br>

        <cfloop INDEX="TheField" list="#Form.FieldNames#">

            #TheField# = #Evaluate(TheField)#<br>

            <cfset TheField = Evaluate(TheField)>

        </cfloop>

    </p>

    Lets try and output the two form fields without using the "form." notation<br>

    FirstName : #FirstName# <br />

    LastName : #LastName#

</cfoutput>


The client variables currently available are:

<cfset nVarCounter = 1>

<cfloop list="#GetClientVariablesList()#" index="whichClientVar">

    #whichClientVar# : #client[whichClientVar]#<br />

    <cfset whichClientVar = Evaluate(whichClientVar)>

</cfloop>

Kevin
  • 83
  • 7

5 Answers5

4

You should always scope your variables. When you use evaluate it runs through the scope order and it pulls the values out of the url scope before it gets to the form scope

You can use associative array notation to pull the data (as seen below).

<cfoutput>
<b>Field Names:</b> #Form.FieldNames#
<p>
    <b>Field Values:</b><br>
    <cfloop INDEX="TheField" list="#Form.FieldNames#">
        #TheField# = #form[TheField]#<br><!--- specify form scope --->
        <cfset myField = structKeyExists(url,TheField) ? url.TheField : form.TheField>        
    </cfloop>
</p>
</cfoutput>
Community
  • 1
  • 1
Matt Busche
  • 14,216
  • 5
  • 36
  • 61
  • Same problem. Try the following. Have different values for the form and URL variables as in the original post. Field Names: #Form.FieldNames#

    Field Values:
    #TheField# = #form[TheField]#
    Lets try and output the two form fields without using the "form." notation
    FirstName : #FirstName#
    LastName : #LastName#

    – Kevin Oct 09 '13 at 21:02
  • the code above cannot return URL variables the way it's constructed. There must be something else wrong in your code. Can you post a self contained repro case we can look at? – Matt Busche Oct 09 '13 at 21:07
  • Do you know of a site like http://jsfiddle.net/ that is for ColdFusion? My code is behind a corporate firewall and can't be made visible and I don't have an external site I can use. – Kevin Oct 09 '13 at 21:15
  • Ahh. I see. ColdFusion is 'sort of' doing what I want by default, but doesn't use the order that I want. My code isn't really working the way that I was wanting it to. I want to to automatically do the equiv of – Kevin Oct 09 '13 at 21:25
  • (I ran out of space on the previous comment) In this example, if FirstName existed as both a url AND a form variable, it would be set to whatever the form value was since it was last. However, in the dynamic code that I was working on, if the variable exists as both a form and url version, my code will return the url version. I do NOT want that to happen. I am guessing that there is a better/different way to go about this, but I'm not sure what it is. – Kevin Oct 09 '13 at 21:26
  • Use a framework and all this messing about has been done for you. FW/1 and Coldbox are both worth considering. – Peter Boughton Oct 09 '13 at 22:17
  • @Kevin _Do you know of a site like jsfiddle.net that is for ColdFusion_ - yes you can try [cflive.net](http://cflive.net). I can't figure out why you are trying to avoid scoping your variables? Typically it is always recommended to scope your variable to avoid exactly what you are experiencing. – Miguel-F Oct 10 '13 at 00:28
  • @Kevin I've updated my answer to first pull the value from the url scope and if it's not there pull the value from the form scope. – Matt Busche Oct 10 '13 at 00:49
2

You can 'copy' the values from form scope and url scope into the variables scope by using structAppend().

structAppend( variables, form, true );
structAppend( variables, url, false );

In the first line, any element of the form scope is copied to the variables scope and if a variable already exists with the same name in variables scope, it will overwrite that value with the value from the form scope.

In the second line, elements form URL scope are copied to variables scope but if a variable already exists in the variables scope, it is NOT overwritten.

You can do this for ANY scope and any other ColdFusion structure. You can also reorder them so that one scope has precedence over the others.

Scott Stroz
  • 7,510
  • 2
  • 21
  • 25
0

In CF 10 or Railo 4, you could use the defaults() function of the Underscore.cfc library to succinctly accomplish what you're trying to do. Example:

// instantiate Underscore library
_ = new Underscore();

// copy values from form and url scopes into the variables scope
_.defaults(variables, form, url);

This function "fills in" any undefined values in the first struct to the values in the subsequent structs. It works from left to right, so in this example it gives precedence to values in form over the values in url.

Disclaimer: I wrote the Underscore.cfc library.

Russ
  • 1,931
  • 1
  • 14
  • 15
-1

Please refer to the following Adobe documentation for order of precedence: http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec09af4-7fdf.html

If you want to reverse this precedence for some reason you should be able to just set all of your FORM fields into the variables scope...

Maybe something like ...

<cfloop collection=#form# item="varName">
  <cfset SetVariable("variables.#varName#", evaluate("FORM." & varName))>
</cfloop>
bking
  • 21
  • 2
  • I had to alter my original post because of a code error. Please give that a shot. You also may want to wrap that code in a isDefined for form.fieldlist, possibly. – bking Oct 09 '13 at 23:23
  • 4
    sorry, but this is not a good answer. You can rewrite your code to `` There's almost never a reason to use `evaluate` or `setVariable` – Matt Busche Oct 10 '13 at 00:47
  • 1
    No need to use setVariable() or evalutae() in this example. Besides, the same can be accomplished with one function call - `structAppend()` – Scott Stroz Oct 10 '13 at 02:20
-2

Thanks for all of the great ideas.

Following is what I ended up going with.

<cfset scopes = "url,client,form">

<cfloop list="#scopes#" index="i">
    <cfloop list="#structKeyList( evaluate( i ) )#" index="j">
            <cfset structInsert( VARIABLES, j, evaluate( i & '["' & j & '"]' ), true ) />
    </cfloop>
</cfloop>


<cfoutput>
    Lets try and output the two form fields without using the "form." notation and make sure that the URL variables are NOT over writing the Form ones<br>
    FirstName : #FirstName# <br />
    LastName : #LastName#<br />

</cfoutput>


<cfdump var="#VARIABLES#" abort="1" label="Combined Variables Scope stuff" />
Kevin
  • 83
  • 7