How to check value in an Array using Coldfusion? - coldfusion

I have the below code:
<cfset abcList = "*,B,b,A,C,a">
<cfset abcList=ListToArray(abcList,',')>
When I output 'abcList' then it is giving me a value but when I use the 'abcList' in <cfif> it's not working. Here is the code which is creating the problem:
<cfoutput>
#abcList[1]# <!---This is giving '*' as Correct o/p--->
<cfif #abcList[1]# eq '*'> <!---Here its going in else--->
list has * at first place
<cfelse>
* is not first
</cfif>
</cfoutput>
Any suggestions on what's wrong in my code?

You don't necessarily need to convert the list to an array. If you are starting from a list variable, you may use Coldfusion list functions to do the same thing without specifying the array conversion.
<cfset abcList = "*,B,b,A,C,a">
<cfif Compare(listGetAt(abcList, 1), '*') EQ 0>
Match
<cfelse>
No Match
</cfif>
Note that most of Coldfusion's string comparisons are not case sensitive. So if you need to test that 'B' is not the same as 'b', you will need to use the compare() function or else use one of the Regular Expression string functions. In this case, compare() returns 0 if string 1 equals string 2. If you do not need case sensitivity, then you may simplify further:
<cfset abcList = "*,B,b,A,C,a">
<cfif listGetAt(abcList, 1) EQ '*'>
Match
<cfelse>
No Match
</cfif>

It also works fine for me. Perhaps you have some extra spaces in the list values? That would skew the results:
<cfset abcList = "#chr(32)#*,B,b,A,C,a">
<cfset abcList=ListToArray(abcList,',')>
<cfoutput>
The value of abcList[1] = #abcList[1]# <br/>
<cfif abcList[1] eq '*'>
list has * at first place
<cfelse>
The else condition was hit because abcList[1] is "(space)*" and not just "*"
</cfif>
</cfoutput>
Try trimming the value first. Also, the # signs around the value are not needed.
<cfif trim(abcList[1]) eq '*'>
....
</cfif>
If that does not work, display the ascii values of both characters. Perhaps they are different than you are thinking.
<cfoutput>
ASCII abcList[1] = #asc(abcList[1])# <br/>
ASCII "*" = #asc("*")# <br/>
</cfoutput>

<cfset abcList = "*,B,b,A,C,a">
<cfset abc=ListToArray(abcList)>
<cfif #abc[1]# eq "*">OK<cfelse>FAIL</cfif>
<cfif abc[1] eq "*">OK<cfelse>FAIL</cfif>
Prints "OK OK" for me. Can you re-confirm it prints something else for you?

Related

Parse the contents of a Coldfusion variable into separate variables

OK, so I've been banging my head against this one for a while and getting nowhere. I've been attempting to take the contents of a variable and parse the contained string into parts that would then be ingested into 5 separate variables. Seems simple enough right? Well, it has not proven to be simple at all, at least for me.
So I have a variable (PageContent) that contains the trimmed content from a CFHTTP request.
The PageContent variable now contains:
<tdnowrapalign=right>07/18/2020 13:00</td>
<tdalign=right>1002.12</td>
<tdalign=right>2,874,887</td>
<tdalign=right>12,766</td>
<tdalign=right>13,038</td>
It seems like there should be an easy way to write a loop that would loop over the tags in the "PageContent" variable assigning the content of each tag to a different variable. But every way I try to parse the data in the variable I either get an error (Complex object types cannot be converted to simple values.) or I end up with the content that I originally had in the "PageContent" variable repeated within the loop.
For instance, if I had a loop that would run through 5 iterations and could grab the contents of the tags assigning each to a variable then the desired result would be:
DateTime = "07/18/2020 13:00"
Elevation = "1002.12"
Storage = "2,874,887"
Outflow = "12,766"
Inflow = "13,038"
After trying every example I could find here and elsewhere online I'm now on something like my 100th attempt. Now I'm trying to use regular expressions to grab the contents of the tags and assign them to variables but no luck there. What I ended up with was the entire contents of the PageContent variable being stuffed into each one of the variables. The result was not really unexpected since I don't know of a way to differentiate between the 3 identical "tdalign" tags, but still it seems like at least the first variable would have worked since the tag was different "tdnowrapalign".
<cfset i=5/>
<cfloop index = "LoopCount" from = "1" to = #i#>
<cfif i EQ 1>
<cfset dataDateTime = Replace(PageContent, "<[tdnowrapalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 2>
<cfset elevation = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 3>
<cfset storage = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 4>
<cfset outflow = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 5>
<cfset inflow = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
</cfif>
<cfoutput>
<cfif isdefined("dataDateTime")>
dataDateTime = #dataDateTime#<br>
</cfif>
<cfif isdefined("elevation")>
elevation = #elevation#<br>
</cfif>
<cfif isdefined("storage")>
storage = #storage#<br>
</cfif>
<cfif isdefined("outflow")>
outflow = #outflow#<br>
</cfif>
<cfif isdefined("inflow")>
inflow = #inflow#<br>
</cfif>
</cfoutput>
<cfset i = i - 1>
</cfloop>
Does anyone know if there is a way to get to the desired outcome I described where I end up with 5 variables containing the contents of the tags contained within the "PageContent" variable?
One way of doing it would be like this
<cfset PageContent = '<tdnowrapalign=right>07/18/2020 13:00</td>
<tdalign=right>1002.12</td>
<tdalign=right>2,874,887</td>
<tdalign=right>12,766</td>
<tdalign=right>13,038</td>' />
<cfset data = ListToArray(PageContent, '</td>', false, true) />
<cfset DateTime = ListLast(data[1], '>') />
<cfset Elevation = ListLast(data[2], '>') />
<cfset Storage = ListLast(data[3], '>') />
<cfset Outflow = ListLast(data[4], '>') />
<cfset Inflow = ListLast(data[5], '>') />
Demo: https://trycf.com/gist/b4f3b630bd1cbdc505d07a7d79b68ef5/acf?theme=monokai

abs not working on lucee coldfusion

I am using the below to format the number I get after calulating the % increase or decrease, which means this number can be positive or a negative number. The below works fine on Coldfusion, but on Lucee it throws an error - can't cast [- 6.50] string to a number value. Any idea how to workaround this.
<cfif money_deposit lt 0>
<cfset testVar = abs(NumberFormat(money_deposit,'99.99'))>
<cfelse>
<cfset testVar = NumberFormat(money_deposit,'99.99')>
</cfif>
You should be able to use javaCast
<cfif money_deposit lt 0>
<cfset testVar = abs(NumberFormat(javaCast("float", money_deposit),'99.99'))>
<cfelse>
<cfset testVar = NumberFormat(money_deposit,'99.99')>
</cfif>
First, remove any empty spaces. In any case, it is good practice to first test whether the input parameter is numeric.
<!--- Remove any spaces --->
<cfset money_deposit = REreplace(money_deposit,"\s","","all")>
<cfif isNumeric(money_deposit)>
<cfif money_deposit lt 0>
<cfset testVar = abs(NumberFormat(money_deposit,'-99.99'))>
<cfelse>
<cfset testVar = NumberFormat(money_deposit,'99.99')>
</cfif>
</cfif>
Number format returns a string
http://docs.lucee.org/reference/functions/numberformat.html
The problem is your formatting mask "99.99" means return a formatted number with two characters before the decimal point, the string value you are getting back is "- 6.50", with an extra space. Try using a mask for numberformat of either "9.99" or "09.99"

Coldfusion 10 cfloop errors

I am getting an error after upgrade from coldfusionOX to coldfusion 10.
Error Occurred While Processing Request Complex object types cannot be
converted to simple values.
The expression has requested a variable or an intermediate expression
result as a simple value. However, the result cannot be converted to a
simple value. Simple values are strings, numbers, boolean values, and
date/time values. Queries, arrays, and COM objects are examples of
complex values. The most likely cause of the error is that you tried
to use a complex value as a simple one. For example, you tried to use
a query variable in a cfif tag.
It occurs at line " cfloop index="local.thisRight" list="#rights#" ". It seems like ColdFusion does not like the "rights" here.
Anyone can give me some help? Thanks so much.
<cfif local.profile.rights.profile.self is not "">
<cfquery name="local.getAffiliations" datasource="#Request.readerDSN#">
SELECT tblPersonsToAffiliations.affiliationID, tblPersonsToAffiliations.rights, tblAffiliations.affiliationType, tblPersonsToAffiliations.relationshipType
FROM tblPersonsToAffiliations INNER JOIN tblAffiliations
ON tblPersonsToAffiliations.affiliationID = tblAffiliations.affiliationID
WHERE tblPersonsToAffiliations.personID IN (#local.profile.rights.profile.self#)
AND (tblPersonsToAffiliations.archived IS NULL
OR tblPersonsToAffiliations.archived = '')
</cfquery>
<cfif local.getAffiliations.recordCount is not 0>
<cfloop query="local.getAffiliations">
<cfif local.getAffiliations.relationshipType is "interested">
<cfset local.thisRelationshipType = "provisionalMember">
<cfif IsDefined("local.profile.rights.#affiliationType#.#local.thisRelationshipType#")>
<cfset local.profile.rights[affiliationType][local.thisRelationshipType] = ListAppend(local.profile.rights[affiliationType][local.thisRelationshipType], affiliationID)>
<cfelse>
<cfset local.profile.rights[affiliationType][thisRelationshipType] = affiliationID>
</cfif>
<cfelse>
<cfset local.thisRelationshipType = "fullMember">
<cfif IsDefined("local.profile.rights.#affiliationType#.#local.thisRelationshipType#")>
<cfset local.profile.rights[affiliationType][local.thisRelationshipType] = ListAppend(local.profile.rights[affiliationType][local.thisRelationshipType], affiliationID)>
<cfelse>
<cfset local.profile.rights[affiliationType][local.thisRelationshipType] = affiliationID>
</cfif>
<cfif isNull(rights)>
<cfelse>
<cfloop index="local.thisRight" list="#rights#" >
<cfif IsDefined("local.profile.rights.#affiliationType#.#local.thisRight#")>
<cfset local.profile.rights[affiliationType][local.thisRight] = ListAppend(local.profile.rights[affiliationType][local.thisRight], affiliationID)>
<cfelse>
<cfset local.profile.rights[affiliationType][local.thisRight] = affiliationID>
</cfif>
</cfloop>
</cfif>
</cfif>
</cfloop>
</cfif>
</cfif>
A bit earlier in your code you do this:
<cfif local.getAffiliations.relationshipType is "interested">
I think you need the same query name prefix in front of "rights" that is used when evaluating "relationshipType".
Try this:
#local.getAffiliations.rights#
HTH!
I am betting it is failing on this line:
<cfloop index="local.thisRight" list="rights" >
You are attempting to use the string "rights" as a list. My first reaction would be that you need to make that:
<cfloop index="local.thisRight" list="#rights#" >

ColdFusion isDefined

I am trying to check to see if data exist in my form If data does not exist I want to assign it to O. How can I do this.
<cfif not isDefined("FORM.Age")>
cfset FORM.Age = "0"
<cfif>
Generally the best practice is considered to be to avoid isDefined. This is because isDefined will search all scopes until it finds a matching variable. So it's more efficient to use structKeyExists, eg:
<cfif NOT structKeyExists(form, "age")>
<cfset form.age = 0>
</cfif>
Also, another way to achieve this is to use cfparam, and specify 0 as the default:
<cfparam name="form.age" default="0">
You're almost there:
<cfif not isDefined("FORM.Age")>
<cfset Form.Age = 0>
</cfif>
Technically what you have is fine once you enclose the cfset in tags < and >. Assuming that omission is just a typo, could it be you are trying to use it with a text field?
Text fields always exist on submission. The value may be an empty string, but the field itself still exists, so IsDefined will always return true. If that is the case, you need to examine the field length or value instead. Then do something if it is empty according to your criteria. For example:
<!--- value is an empty string --->
<cfif NOT len(FORM.age)>
do something
</cfif>
... OR
<!--- value is an empty string or white space only --->
<cfif NOT len(trim(FORM.age))>
do something
</cfif>
... OR
<!--- convert non-numeric values to zero (0) --->
<cfset FORM.Age = val(FORM.Age)>
There are actually two things you want to to ensure. First, make sure this page was arrived at by submitting the proper form. Next, ensure you have a numeric value for the form.age variable. Here is an example of how you might want to code this:
<cfif StructKeyExists(form, "age") and cgi.http_referrer is what it should be>
<cfif IsNumeric(form.age) and form.age gt 0>
<cfset AgeSubmitted = int(form.age)>
<cfelse>
<cfset AgeSubmitted = 0>
</cfif>
...more code to process form
<cfelse>
...code for when page was not arrived at properly
</cfif>

How To Loop Through Two Lists?

I need to join the output of two separate lists together to output in a CFMAIL, and I'm wondering what the best way to approach this is.
I have two form fields: first_name and last_name
The fields have up to 5 names in each. I need to loop through those names and join the first and last names, then output them to unordered list. I am having trouble visualizing what the right approach to accomplish this is.
Can someone suggest a method in CFML (I don't know CFSCRIPT very well).
Thanks!
EDIT: I should have added that both fields will always have the exact same number of entries. Thanks to all that answered -- proof that there are a lot of ways to skin a cat :)
I would do something like
<cfloop from="1" to="#ListLen(firstnames)#" index="i">
#ListGetAt(firstnames,i)# #ListGetAt(lastnames,i)#<br>
</cfloop>
If this were a list of 5000 you would be better off putting it in a structure or an array, but for a list of ~5 this should be sufficient.
I think this would be the easiest way to accomplish this.
<!--- Create a names container --->
<cfset names = "<ul>">
<!--- Fill some dummy containers --->
<cfset first = "thomas,henry,philip,john,rony">
<cfset last = "smith,baker,crowe,ryan,jones">
<!--- Loop through the lists and append them to the container string --->
<cfloop index="name" to="#listLen(first)#" from="1">
<cfset names &= "<li>" & ListGetAt(first,name) & " " & ListGetAt(last,name) & "</li>">
</cfloop>
<cfset names &= "</ul>">
<cfoutput>#names#</cfoutput>
I would add in a check to make sure that your list values exists at each index, otherwise you will get errors. I would also add in a check to loop through whichever list is greater so that you get all values just in case someone doesn't enter exactly 5 in both:
<Cfset firstnames="Matt,Ian,Brandon,Sam,Tom">
<cfset lastnames="Jones,Smith,Weiss">
<!--- SEE WHICH LIST IS LONGER AND SET THAT AS THE ONE THAT WE WILL USE FOR THE LOOP --->
<cfif ListLen(firstnames) gte ListLen(lastnames)>
<cfset primary=firstnames>
<cfelse>
<cfset primary=lastnames>
</cfif>
<cfset myOutput="<ul>">
<cfloop from="1" to="#ListLen(primary)#" index="i">
<Cfset myOutput &= "<li>">
<cfif ListLen(firstnames) gte i>
<cfset myOutput &= ListGetAt(firstnames,i)>
</cfif>
<cfif ListLen(lastnames) gte i>
<cfset myOutput &= " " & ListGetAt(lastnames,i)>
</cfif>
<Cfset myOutput &= "</li>">
</cfloop>
<Cfset myOutput &= "</ul>">
<cfoutput>#myOutput#</cfoutput>
You could use the "list" attribute with CFLOOP although it means combining list functions within the output. Here is an example though of how it could be done and it makes the assumption the two lists will always have the same lengths. If these names are keyed in by users then I might be afraid of if they put in a comma since that would throw things off with any sort of looping.
<cfset lstFirstNames = "John,Bob,Tom,Jeff" />
<cfset lstLastNames = "Smith,Doe,Rodriguez,Horan" />
<cfloop list="#Variables.lstFirstNames#" index="FirstName" />
#FirstName# #ListGetAt(Variables.LastNames, ListFind(Variables.lstFirstNames, FirstName))#<br />
</cfloop>
try:
<cfset lstFirstNames = "John,Bob,Tom,Jeff" />
<cfset lstLastNames = "Smith,Doe,Rodriguez,Horan" />
<cfloop list="#Variables.lstFirstNames#" index="FirstName">
<cfoutput>#FirstName# #ListGetAt(Variables.lstLastNames, ListFind(Variables.lstFirstNames, FirstName))#</cfoutput><br />
</cfloop>