2

I have to loop over the array of street addresses and insert the data into database. User always provide one line of address and some times two. I am trying to loop the array and dynamically set address_1 and address_2(if exists or NULL if not), but it does not work for me.

Image of array dump

Here is what I have:

<cfset address_1 = #jsonData.addresses.customer.street[1]#>
<cfif isDefined(jsonData.addresses.customer.street[2])>
    <cfset address_2 = #jsonData.addresses.customer.street[2]#> 
<cfelse>    
    <cfset address_2 = "">
</cfif>

When I run it, I get this: Parameter 1 of function IsDefined, which is now Suite 300, must be a syntactically valid variable name.

2
  • 1
    This has nothing to do with the error, but ... it's never too early or too late to break the habit of overusing pound # signs in CF :-) Sadly a lot of devs, including myself, learned that from the official documentation. Years later I was VERY surprised to learn how infrequently they're actually needed... Mostly when using <cfoutput>, or if a CF variable is wrapped in quotes (that's usually avoidable). So in the code above, NONE of those pound signs are actually needed :-). Commented Aug 8, 2019 at 17:37
  • There's arrayIsDefined Commented Jun 21, 2021 at 12:59

2 Answers 2

5

The Simple Answer to this question would be to just use ArrayIsDefined

<cfif ArrayIsDefined(yourArray, index)>
    <!--- perform your logic here --->
 </cfif>

this way you can also prevents the possible errors

Sign up to request clarification or add additional context in comments.

Comments

4

IsDefined can only tell you if a variable named jsonData.addresses.customer.street exists. It can't examine the contents, so it's the wrong function for this scenario.

Assuming the street array always exists, just check it's size using the member function len(), or ArrayLen(). If the size is >= 2, then you know the 2nd address exists.

<!--- Option 1: Member function len()  --->
<cfif jsonData.addresses.customer.street.len() gte 2 > 
   2nd address exists, do something 
</cfif>

<!--- Option 2: ArrayLen() --->
<cfif arrayLen(jsonData.addresses.customer.street) gte 2 > 
   2nd address exists, do something 
</cfif>

Dynamic "address_x" variables

Depending on what you're ultimately doing, you might consider leaving the address information as an array, because it's easier work with when dealing with a dynamic number of elements. However, if you prefer you could also define separate address_x variables dynamically, using <cfloop array="..">

<!--- demo data --->
<cfset jsonData.addresses.customer.street = ["Line1","Line2","Line3"]>

<cfloop array="#jsonData.addresses.customer.street#" item="line" index="pos">
    <!--- Use the current position to name variables xx_1, xx_2, xx_3 --->
    <cfset variables["address_"& pos] = line>
</cfloop>

<!--- results --->
<cfdump var="#variables#">

Results:

Image of generated variables


About Original Error

A frequently misunderstood detail about IsDefined is that the function expects the name of a variable, which is usually a plain string in quotes, like "myVariable". Since there are no quotes surrounding the variable name here:

<cfif isDefined( jsonData.addresses.customer.street[2] )>

... that variable gets evaluated and its value is what's actually being passed into IsDefined(). So the code ends up checking the wrong variable name:

<!--- code is really doing this (thinks address[2] is the variable name) --->
<cfif isDefined("Suite 300")>

The reason that triggers an error is because IsDefined() only accepts valid CF variable names. So it can't be used on variable names containing special characters (spaces, square brackets, etc..) - meaning it won't work with a variable named Suite 300. That limitation is one of the reasons why StructKeyExists() is usually recommended instead.

3 Comments

Thank you once again. I marked the question as answered (it works), but ... what if I dot not know the number of address fields and I want to dynamically <cfset> as many of them as user enters? This is why I was asking about accessing array by the element.
I've never used this syntax before: <cfset variables["address_"& pos] = line>. I would write it as: <cfset "address_"pos>. Is this a preferred way of doing it?
The first method is called structure notation, and is the preferred way to create dynamic variables, i.e. someStruct["keyName"] = "foo". It forces you to scope your variables, which is a best practice. Since all CF scopes are structures, that syntax can be used with any scope (variables, local, application, etc..). I've only seen that 2nd syntax in legacy code, ie <cfset "address_"& pos = "foo">. Folks used to use it a lot before CF scopes were structures, and it was harder to create dynamic variables.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.