advanced cfif statement - coldfusion

How would I create this statement in CF?
<cfif (not isdefined("URL.room") or #URL.room# EQ "")
and (not isdefined("URL.system" or #URL.system# EQ "")
and (not isdefined("URL.date") or #URL.date# EQ "")>
Obviously the parentheses don't work, but illustrate what I am trying to accomplish. What is the syntax for this?
EDIT:
Ok, I understand how to use EQ and all that. I posted this in a bit of a hurry. My question is about the parentheses. Is it syntactically correct to use them this way?

EDIT: Ok, I understand how to use EQ
and all that. I posted this in a bit
of a hurry. My question is about the
parentheses. Is it syntactically
correct to use them this way?
Syntactically, yes. The code's syntax is correct and will not throw syntax errors.
However, it's not necessarily the best way to do it. At the very least you should have linebreaks in there, to make it more readable, like so:
<cfif (not isdefined("URL.room") or URL.room EQ "")
and (not isdefined("URL.system" or URL.system EQ "")
and (not isdefined("URL.date") or URL.date EQ "")
>
And I would be more inclined to write it like this:
<cfif NOT
( ( isDefined('Url.Room') AND Len(Url.Room) )
OR ( isDefined('Url.System') AND Len(Url.System) )
OR ( isDefined('Url.Date') AND Len(Url.Date) )
)>
Because that's much more readable, and makes it more obvious that each row is checking the same thing.
That is assuming I was doing this in a single IF statement, anyway.
If you start getting lots of conditions to check, you might want to consider doing something like this instead:
<cfset FieldList = "Room,System,Date" />
<cfset AllFieldsValid = true />
<cfloop index="Field" list="#FieldList#">
<cfif NOT ( StructKeyExists(Url,Field) AND Len(Url[Field]) )>
<cfset AllFieldsValid = false />
<cfbreak/>
</cfif>
</cfloop>
<cfif AllFieldsValid>
...
Which might look intimidating at first, but is much easier to maintain - you just add a new item to FieldList (and you may already have a variable which serves that purporse).
Anyway, hopefully all this helps - let me know if any questions on it.

I'd prefer...
<cfparam name="URL.room" default="">
<cfparam name="URL.system" default="">
<cfparam name="URL.date" default="">
<cfif len(URL.room) EQ 0 and len(URL.system) EQ 0 and len(URL.date) EQ 0>
...
</cfif>
Or if you're comfortable with mixing non-boolean functions and boolean expression
<cfif len(URL.room) and len(URL.system) and len(URL.date)>
...
</cfif>

replace the = with eq

In CFML the comparison operators use characters rather than symbols:
== EQ
!= NEQ
> GT
>= GTE
< LT
<= LTE
Similarly with boolean operators:
! NOT
&& AND
|| OR
You can still use the traditional symbols in CFScript mode.
Also worth mentioning that Railo, an alternative CFML engine to Adobe ColdFusion, allows you to use the symbols in tag-based code, if there is no ambiguity with closing tag (e.g. the condition is wrapped in parentheses).

#Henry:
<cfif len(URL.room) EQ 0 and len(URL.system) EQ 0 and len(URL.date) EQ 0>
...
</cfif>
Shorter:
<CFIF Len(URL.room) AND Len(URL.system) and Len(URL.date)>
Len() is better than EQ ""

You need to think your logic through a bit.
You can't check to see if room is an empty string if it is undefined.
Probably what you really need is :
If (structkeyexist(URL,"room") and (Len(URL.room) eq 0 or URL.room eq 'blah'))
Do something
Else
Do something else
I'm afraid stackoverflow cuts off your example condition on my phone, but hopefully this illustrates what you need to do.

Related

ColdFusion checking empty form fields

I am very new to ColdFusion and was curious if someone could tell me how to check to see if a form field is empty or not.
For example let's say we set it up like this:
<cfinput
type="text"
name="firstName"
id="firstName"
value="#form.firstName#"
>
How do I call this later to use it in another form? I tried many things but I am missing something somewhere.
<cfif (form.firstName) EQ 0>
You can check if the length of the field is 0, using trim would remove any leading or trailing spaces.
<cfif len(trim(form.firstName)) EQ 0>
I have always use a two fold check. IsDefined evaluates a string value to determine whether the variable named in it exists.
<CFIF NOT IsDefined("FORM.firstname") OR
FORM.firstname EQ "">
Reference: http://help.adobe.com/livedocs/coldfusion/8/htmldocs/help.html?content=functions_in-k_14.html
The most straightforward way is:
<cfif form.firstName IS "">
It simply checks to see if the specified form field is an empty string ("").
Another way of writing the same thing would be:
<cfif len(form.firstName) EQ 0>
This checks to see if the length of the form field value is 0 (empty string).
This second method can be shortened a little bit?
<cfif len(form.firstName)>
Assume that form.firstName is empty. This would then become . In boolean evaluation, 0 is false. Assuming the value was not empty, it would become . A non-zero number evaluates to true.
Some developers prefer checking for emptiness by checking comparing against an empty string. See len(x) better or x NEQ "" better in CFML?
<cfif trim(form.firstName) NEQ "">
<cfscript> is also an option
<cfscript>
if (trim(form.firstName) != "") {
...
Yoda conditions work too
<cfscript>
if ( "" != trim(form.firstName)) {

Coldfusion dynamic variable naming

It's possible with coldfusion convert this php code?
if ( $_GET[ 'bSortable_'.intval($_GET['iSortCol_'.$i]) ] == "true" ){
//do something...
}
I have tried something as:
if( structKeyExists( url , "bSortable_[iSortCol_[#i#]]" ) ) {
}
But seems not working....probably I should try another way to make this?
The variables are two:
bSortable_1 = true;
iSortCol_1 = 1;
I should obtain bSortable_1 value....
I am not much familiar with PHP but it seems that you are passing bSortable_1, iSortCol_1 kind of query variable to make sorting of table. I guess below code should work foe you.
<cfset url.bSortable_1 = 1>
<cfset url.iSortCol_1 = 1>
<!--- Option 1 --->
<cfif structKeyExists(URL,"bSortable_#URL.iSortCol_1#")>
<cfoutput>Exists</cfoutput>
</cfif>
<!--- Option 2 --->
<cfset i = 1>
<cfif URL['bSortable_#URL['iSortCol_#i#']#']>
<cfoutput>Exists</cfoutput>
</cfif>
Although I found this is so complex. I will suggest go for some nicer option.
This is explanation requested in the comments. There are at least two url variables available, bSortable_1 and iSortCol_1. Both the php code and Pritesh's answer have this sort of structure.
<cfif somethingabout_bSortable_1.somethingabout_iSortCol_1>
do something
By treating the variables separately, my structure would resemble this:
<cfif somethingabout_bSortable_1 and (or or) somethingabout_iSortCol_1>
do something
Going to the StructkeyExists function, but with static values, it would be this
<cfif StructKeyExists(url, "bSortable_1") and StructKeyExists(url, "iSortCol_1")>
do something
For dynamic values, I don't know what would work so I would have to find out. Having said that, the first thing I'd try is:
<cfloop from = "1" to = SomeMaximum index = "i">
<cfif StructKeyExists(url, "bSortable_#i#") and StructKeyExists(url, "iSortCol_#i#")>
do something
closing tags

Having some trouble understanding loops

I created this for some reason neither one of the queries are being updated
<cfloop index="i" from="1" to="#ArrayLen(location)#">
<cfif location[i] NEQ "" AND #locationID# EQ "" >
<cfquery Name="UpdateAddActivity" DATASOURCE="#DS#">
INSERT INTO tblProjectLocations
(
projectID,
locationID
)
VALUES
(
#ProjectName#,
#location[i]#
)
</cfquery>
</cfif>
<cfif location[i] EQ "" AND #locationID# NEQ "" >
<cfquery Name="UpdateAddActivity" DATASOURCE="#DS#">
DELETE FROM tblProjectLocations
WHERE locationID = #locationID# AND projectID = #ProjectName#
</cfquery>
</cfif>
</cfloop>
Am I looping correctly? It doesn't seem like to me that the accumulator is ever going to be updated but loops are done this way every place that I've looked.
Your cfloop tag is fine - you only need index/from/to attributes for a basic loop.
The index variable is incremented (and the loop re-processed) at the position of the closing tag. Or to put it another way, the body code is executed once for each index value between from and to (inclusive).
For information, you can change the default increment (of 1) by specifying the step attribute (though that obviously doesn't make sense for an array loop).
When your code isn't performing as expected, you can debug it with the dump tag:
<cfloop ... >
...
<cfdump var=#locationID# abort />
...
</cfloop>
The abort attribute will stop processing - the loop will not iterate and the current page content will be returned (it's shorthand for specifying cfabort tag separately.
You can use multiple dumps, and the label attribute to help identify which is which, but obviously if using abort attribute make sure only the last one has it.
As has been mentioned locationID isn't defined in the snippet you've provided, so may be the issue.
Sometimes spaces can cause issues - you may want to use the trim function to ensure you're dealing with empty strings (though blindly wrapping trim functions everywhere is ugly - always try if possible avoid introducing spaces).
Shortcut Array Looping
The from/to loop you've got there is only one type of cfloop - there are others.
Specifically, when you don't need the numeric index, there is a shorthand array loop:
<cfloop index="CurLocation" array=#Location# >
...
</cfloop>
Which is equivalent to:
<cfloop index="i" from=1 to=#ArrayLen(Location)# >
<cfset CurLocation = Location[i] />
...
</cfloop>
But without the unused i variable. (If you need the i variable, stick to from/to.)
Note that inside a function you should almost always write index="local.i" and index="local.CurLocation" to ensure the variables are appropriately scoped. This isn't unique to loops - it applies to any tags that create variables. You can also do <cfset var i = 0 /> prior to the loop to do the same thing.
Unrelated Issues
There are a couple of other issues with your code.
Most importantly, the code you're showing is potentially at risk of SQL injection. You should almost never write SQL with bare hashes in, and instead parameterise your queries - using cfqueryparam tag - to solve this. (In the situations where you can't use parameters (e.g. within ORDER BY) make sure you have appropriately sanitized any dynamic text.
Less important -- it doesn't change how the code works, but does betray a lack of experience and understanding -- are the superfluous hashes around locationID. A simplified explanation is that you generally only need #s inside strings (i.e. where the contents would otherwise be treated as text, rather than being a variable's value.)
When in doubt, look at your data.
<cfoutput>
<cfloop index="i" from="1" to="#ArrayLen(location)#">
i is #i# <br>
<cfif location[i] NEQ "" AND locationID EQ "" >
true location is #location[i]# <br>
<cfelse>
false location [i] is is #location[i]# and
locationid is #locationID# <br>
</cfif>
<cfif location[i] EQ "" AND locationID NEQ "" >
same as above
</cfif>
</cfloop>
</cfoutput>
Then you'll know why you are not getting the results you expect.
As long as there are items in your location array, the loop will run and the CFLoop tag will take care of incrementing i.
What I'd guess is happening is that you are checking two conditions within the loop and if neither match, no code will run. You're handling these:
location[i] NEQ "" AND #locationID# EQ ""
location[i] EQ "" AND #locationID# NEQ ""
but not these:
location[i] EQ "" AND #locationID# EQ ""
location[i] NEQ "" AND #locationID# NEQ ""
Could that be it?

Coldfusion Regex question

I currently have a coldfusion regex that checks whether a string is alphanumeric or not.
I would like to open that up a bit more to allow period and underscore characters. How would I modify this to allow that?
<cfset isValid= true/>
<cfif REFind("[^[:alnum:]]", arguments.stringToCheck, 1) GT 0>
<cfset isValid= false />
</cfif>
Thanks
No need for cfif - here's a nice concise way of doing it:
<cfset isValidString = NOT refind( '[^\w.]' , Arguments.StringToCheck )/>
Alternatively, you can do it this way:
<cfset isValidString = refind( '^[\w.]*$' , Arguments.StringToCheck ) />
(To prevent empty string, change * to +)
This method can make it easier to apply other constraints (e.g. must start with a letter, etc), and is a slightly more straight-forward way of expressing the original check anyway.
Note that the ^ here is an anchor meaning "start of line/string" (with $ being the corresponding end), more information here.
This should do it.
<cfset isValidString= true/>
<cfif REFind("[^[:alnum:]_\.]", arguments.stringToCheck, 1) GT 0>
<cfset isValidString= false />
</cfif>
Also using "isValid" for a variable name is not a great practice. It is the name of a function in ColdFusion and could cause you issues someday.
Would this work for you?
refind("[\w\d._]","1234abcd._")

How to check value in an Array using 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?