I am getting an an error "Invalid CFML construct found"
iif(stImages[id][1]["seolink"] is not "", stImages[id][1]["seolink"], stImages[id][1]["url"]) />
what i am doing here wrong?
Try:
iif(stImages[id][1]["seolink"] is not "", DE(stImages[id][1]["seolink"]), DE(stImages[id][1]["url"])) />
For those readers playing from home (as it were), IIF can be an unruly beast because of the double evaluation it does. So
#IIF(myVal EQ "", "thisThing", "thatThing")#
LOOKS like it will simply return the first or second strings, but in fact it will return the content of the VARIABLES "thisThing" or "thatThing" (or throw an error that they don't exist). So say it with me: "IIF() and DE() GO TOGETHER LIKE MUTUALLY BENEFICIAL PARASITIC LIFEFORMS". "DE" as in "Delayed Evaluation". So if you want the above statement to return the first or second string, you need:
#IIF(myVal EQ "", DE("thisThing"), DE("thatThing"))#
Now, you can certainly use this feature to evaluate a field twice and NOT use "DE()", but that means you're using some kind of dynamic variable name, and it could be argued that doing that isn't best practice. Not that I haven't done that exact thing, but it should be copiously commented, because if you don't the person who maintains the code after you will probably want to kill you.
By the way, there's no mystery to "DE()". These two statements are equivalent:
#DE("thisThing")#
#"""thisThing"""#
See what's going on? "DE()" simply puts double quotes around something. So one set of quotes gets "stripped off" the first time it gets evaluated, and then the quoted string gets returned from the function. Clear as mud?
See why people don't like IIF? It's very handy in certain situations, but is a contextual mess and contributes to code that makes people go "HWUUUH??" So that's why people say to avoid it if possible.
I would avoid iif where you can,
iif(stImages[id][1]["seolink"] is not "", DE(stImages[id][1]["seolink"]), DE(stImages[id][1]["url"])) />
<cfif stImages[id][1]["seolink"] is not "">#stImages[id][1]["seolink"]#<cfelse>#stImages[id][1]["url"]#</cfif>
or if you have ColdFusion 9
<cfset stImages[id][1]["seolink"] is not "" ? #stImages[id][1]["seolink"]# : #stImages[id][1]["url"]# />
Related
I am having a heck of a time trying to figure this out. I'm trying to replace this evaluate function.
<cfoutput>
#evaluate('#qry#.#editVal#')#
</cfoutput>
But I just can't seem to work it out. Both qry and editVal are in the variables scope and when using evaluate it returns a value for instane the value of
#qryVitals.PULSE#
I just can't seem to get the notation right to interpret it. Any help would be greatly appreciated.
#evaluate('#qry#.#editVal#')# is equivalent to #VARIABLES[qry][editVal]#.
As noted by #Leigh, if VARIABLES[qry] is of type query, you have to specify the row number as well, e.g. #VARIABLES[qry][editVal][1]#.
I recently had the need to match against two strings in ColdFusion and ran into this scenario during my loop:
<cfif "0" IS NOT "NO">
Generally during the loop it looks something like this:
<cfif "AM" IS NOT "BA">
Now both of these values were variables (I wasn't just typing it out for fun) and I was using "0" as a default value for the first variable to match against (since the second variables would never be 0) but both of these values changed in the loop I was running. I easily fixed this by setting my default value to -- instead of 0 but I tried researching and found nothing indicating there was a way to get around the falsey nature of strings when evaluating them.
Is there no Operator or trick to match on the strings themselves and ignore their truthyness or falseyness in ColdFusion?
The compare function will help you. This:
writedump(compare("0", "NO"));
returns -1.
This page will tell you what that means.
I am trying to convert the results of a query into an array
this.arLibrary = ValueList(qryLibrary.ID).ListToArray();
And I get the following error
Detail A script statement must end with ";".The CFML compiler was
processing:A script statement beginning with
this.arLibrary on line 43, column 9.A cfscript tag
beginning on line 21, column 2. KnownColumn -1 KnownLine -1
KnownText <unknown> Line 43 Message Invalid construct.
Snippet this.arLibrary =
ValueList(qryLibrary.ID).
StackTrace
This does work
temp = ValueList(qryLibrary.ID);
this.arMetricLibActive = temp.ListToArray();
It makes me wonder if ValueList() is a string
Yes, it's a string. The error is a parsing issue in the CFML engine. The same syntax works fine in Lucee. File a bug like Henry suggested.
Here's an example in the CommandBox REPL
CFSCRIPT-REPL: foo = queryNew('bar')
{
"COLUMNS":[
"BAR"
],
"DATA":[
]
}
CFSCRIPT-REPL: valueList( foo.bar ).listToArray()
[
]
James, it'd be useful if you read error messages when they are presented to you: they generally contain pertinent information. I don't mean this in a "stating the obvious" sort of way, but rather that it's actually a very important part of troubleshooting problems. You are faced with an error message from the compiler, which means the error occurred when the source code was being compiled. However you are asking a question about data types, which - in a loosely and dynamically typed language like CFML - is a runtime consideration. "Runtime" implies "when the code is being run" which is intrinsically after the code is compiled. If the code can't compile: it won't be run.
So the issue is not whether valueList() returns a string or anything like that.
The issue here is that there is a bug in ColdFusion's CFML parser, and it is not able to interpret this expression:
ValueList(qryLibrary.ID).ListToArray()
I don't know why there's a problem with this: there should be no problem with parsing the calling of a method on another function call's return value; and indeed it seems to be a peculiarity of using valueList() like this, as opposed to built-in functions in general.
File a bug.
As for what to do about it in your code in the meantime, I think Dan is right: generally one can use a query column as an array anyhow, provided one uses bracket notation to reference the column, eg: qryLibrary["ID"]. Brad draws attention to this not working on Lucee, but... this is neither here nor there, and just something that Lucee needs to deal with. There was a bug raised for this in Railo - https://issues.jboss.org/browse/RAILO-641 - but they declined to address it, with only semi-valid reasoning.
Epilog:
This works on ColdFusion 2016 and above
<cfscript>
qryLibrary = QueryNew("ID", "varchar");
qryLibrary.addrow({"id" : "cat"});
qryLibrary.addrow({"id" : "dog"});
qryLibrary.addrow({"id" : "fish"});
writedump(qryLibrary);
arLibrary = ValueList(qryLibrary.ID).ListToArray();
writedump(arLibrary);
</cfscript>
https://cffiddle.org/app/file?filepath=6588296c-5e4d-49a4-894b-4986513e9e30/0ecde857-6d28-4e43-88a7-7830c109ab11/84cd7e81-16f8-43d7-b4c9-5490b1b5d007.cfm
The code:
<cfset LOCAL.temp = 'something==a descript >= ive value' />
<cfdump var="#ListToArray(LOCAL.temp, '==')#" />
What I expect is an array with two indices what I get is an array with three indices, CF is also splitting at the single equals sign.
Is anyone else experiencing this behavior or can explain what is going on?
This is expected behaviour. As described in the docs, ListToArray uses single-character delimiters (by default).
One solution is to use split:
Temp.split('==')
(This is making use of the underlying Java string.split method, which splits a string at every match of a specified regex, and works on all Java-based CFML engines, though produces a Java String Array - which can't be directly manipulated with CF's ArrayAppend and related functions, unless it is first converted. ).
Since you're on CF9, you can also use the new multi-char delimiter flag, by setting the fourth argument to true:
ListToArray(Temp,'==',false,true)
I've been thrown into ColdFusion for a very simple assignment. The application has some logic to display "help codes" (let's not get into what is a help code), however, the logic is buggy and needs to be fixed. Given a two-letters code, a 1-4 digits number, and another 1-2 digits number, I would need to display them like this printf call would:
printf("%s%04d%02d", letterCode, bigNumber, smallNumber);
If you're not familiar with the printf function, it accepts a format string (the first parameter), and writes the other variables in it according to the given format. %s means "write a string" and %d means "write a number"; %0zd means "write a number and pad it with zeroes so it's at least z characters long (so %04d means "write a number and pad it with zeroes so it lengths at least 4 digits).
Here are a few examples with %s%04d%02d:
"AD", 45, 12: AD004512
"GI", 5121, 1: GI512101
"FO", 1, 0: FO000100
However, it's my very first time with ColdFusion, and I couldn't find anything like printf or sprintf to format strings.
The other guy, who doesn't work here anymore, resorted to a (non-working) loop, and I thought it would be better to use library code instead of actually fixing the loop, since anyways I might need to do similar things again.
<cfset bigNumberPadded = NumberFormat(bigNumber,"0000")>
<cfset smallNumberPadded = NumberFormat(smallNumber,"00")>
<cfoutput>#letterCode##bigNumberPadded##smallNumberPadded#<cfoutput>
Or alternatively... as suggested by bpanulla, and corrected by Leigh
<cfset args = ["AD", javacast("int", 45), javacast("int", 12)]>
<cfset output= createObject("java","java.lang.String").format("%s%04d%02d", args) >
You can use NumberFormat to pad a number with leading zeros in CF.
<cfoutput>#letterCode##NumberFormat(bigNumber, '0000')##NumberFormat(smallNumber, '00')#</cfoutput>
There's lots of ways to do this in the Java layer underpinning ColdFusion. Here's one Java resource:
http://download.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html
Make instances of the Java classes you need with CFOBJECT or CreateObject.
I am assuming you are displaying these to a webpage? If so, I would use a switch/case statement. Since you said "given a two-letter code...", a switch/case would work well. For example:
<cfswitch expression="#twoLetterCode#">
<cfcase value="aa12348">%s%04d%02d</cfcase>
<cfcase value="bb23456">%s%05f%01e</cfcase>
<cfcase value="cc97641">%s%08g%10j</cfcase>
<cfdefaultcase>%s%04d%02d</cfdefaultcase>
</cfswitch>
Or you could use an if/else instead. But the main point (to answer your question) is that in ColdFusion you just type out the display characters (be it help codes, or text, or whatever). You don't need to use a special function to display text to the page.