Assigning Variables Within A CFLoop Condition In ColdFusion

Posted August 4, 2009 at 1:59 PM by Ben Nadel

Tags: ColdFusion

This morning, when I was exploring ColdFusion 9's new ArrayDelete() function, I actually stumbled upon a feature in ColdFusion that I had never tried before. This is something that I often do in Javascript, which is the only reason I actually tried it this morning without thinking. What I'm talking about is assigning a value to a variable from within the Condition of a CFLoop tag.

Often times, the Condition attribute of a CFLoop tag simply checks to see if a condition is true or false. Something like this:

  • <cfloop condition="(arrayLen( someData ) GT 5)"> .... </cfloop>

Here, our CFLoop tag will continue looping while the array, someData, has a length greater than five.

What I discovered this morning, however, was that if the Condition attribute contains a variable assignment, not only will the variable be assigned successfully, it will then also be further evaluated as a boolean:

  • <!--- Create a list of girls. --->
  • <cfset girls = "Sarah,Molly,Sarah,Joanna,Sarah" />
  •  
  • <!---
  • Keep looping over the girls and deleting the name "Sarah"
  • from the list. In the Condition attribute we are going to
  • BOTH assign a variable and test it's boolean value.
  • --->
  • <cfloop condition="targetIndex = listFind( girls, 'Sarah' )">
  •  
  • <!---
  • Delete instance of Sarah using the stored index value
  • from our condition. Note: this is not a peronal thing -
  • Sarah is a really aweosme girl.
  • --->
  • <cfset girls = listDeleteAt( girls, targetIndex ) />
  •  
  • <!--- Output the notification. --->
  • Delete Sarah at: #targetIndex#<br />
  •  
  • </cfloop>

Here, the Condition of the CFLoop tag gets the list index of a given value and assigns it to the variable, targetIndex. TargetIndex is, itself, then evaluated as a boolean condition, determining whether or not the CFloop should continue executing. And, running the above code, we get the following output:

Delete Sarah at: 1
Delete Sarah at: 2
Delete Sarah at: 3

Sweet-ass-sweet, it works like a charm!

Ironically, the same functionality is not available in a WHILE loop within CFScript. The attempt to recreate this in CFScript:

  • <cfscript>
  •  
  • // Assign girls list.
  • girls = "Sarah,Molly,Sarah,Joanna,Sarah";
  •  
  • // Keep looping while Sarah can be found.
  • while (targetIndex = listFind( girls, "Sarah" )){
  •  
  • // Delete target element.
  • girls = listDeleteAt( girls, targetIndex );
  •  
  • // Output results.
  • writeOutput( "Delete Sarah at: #targetIndex#<br />" );
  •  
  • }
  •  
  • </cfscript>

... throws the following ColdFusion compile time error:

ColdFusion was looking at the following text: = The CFML compiler was processing: A script statement beginning with while on line 41, column 9.

If you want to, you can sort of hack the CFScript-based FOR loop to act this way, but it just looks junky:

  • <cfscript>
  •  
  • // Assign girls list.
  • girls = "Sarah,Molly,Sarah,Joanna,Sarah";
  •  
  • // Keep looping while Sarah can be found.
  • for (
  • targetIndex = listFind( girls, "Sarah" ) ;
  • listFind( girls, "Sarah" ) ;
  • targetIndex = listFind( girls, "Sarah" )
  • ){
  •  
  • ...
  •  
  • }
  •  
  • </cfscript>

So, I guess the only thing appropriate to say at this point is, In your face CFScript!! Ok, ok, all joking and feelings of tag-superiority aside, I am quite happy to have found this feature available in conditional CFLoop tags.


You Might Also Be Interested In:



Reader Comments

Aug 4, 2009 at 2:11 PM // reply »
5 Comments

It may be just a syntax over sight. Replacing = with EQ fixes the error. However, the code using EQ will still throw an error.

"Variable TARGETINDEX is undefined."


Aug 4, 2009 at 2:13 PM // reply »
11,314 Comments

@Steve,

Right, because EQ turns it from an assignment into a comparison. That will work, but because there is no assignment, the targetIndex is no longer valid.


Aug 4, 2009 at 2:15 PM // reply »
25 Comments

Apparently Adobe dropped the ball with "everything you can do with tags you can do with script", eh? Of course, I'd probably "fix" that code by adding the second equals sign (to make an equality instead of an assignment) if I saw it.

Here's a better way with CFSCRIPT:

while (true) {
targetIndex = listFind(girls, "Sarah");
if (targetIndex EQ 0) {
break;
}
girls = listDeleteAt(girls, targetIndex);
}


Aug 4, 2009 at 2:15 PM // reply »
5 Comments

@Ben

Ahh, I gotcha. I really haven't used the condition attribute much, maybe only a handful of times. Good to know though!


Aug 4, 2009 at 2:24 PM // reply »
11,314 Comments

@Barney,

Yeah, that is definitely a better way. I was just trying to translate the variable-assignment-as-part-of-operator functionality.

The biggest discrepancy that I'm seeing in CFScript is CFHeader and CFContent. I cannot find any information on these.

@Steve,

Yeah, condition is the most popular loop feature. Heck, have the time I use it, my condition is "True" as in Barney's example, although mine is tag-based.


Aug 11, 2009 at 5:58 PM // reply »
19 Comments

I like this, it feels gooood. Will def be useful. Thanks Ben!


Sep 24, 2009 at 1:24 PM // reply »
29 Comments

Did some other tests.

Type 0

<cfloop condition="(x = 0)"></cfloop>

This doesn't work. Error: "Invalid CFML construct found on line 1 at column 5. ColdFusion was looking at the following text: ="

This seems different than normal expressions which use parentheses as precedence.

Type 1

<cfloop condition="x = 0"></cfloop>

This works, but maybe not as one might expect. The loop never runs. An assignment loop takes the value of the variable as the condition value.

This is in common with C, C++, and Perl. But not Python or Ruby.

No biggie. Until you see type 3.

Type 2

<cfloop condition="x = reFind(p, s)"></cfloop>

This works great! Thanks CF team.

Type 3

<cfloop condition="x = reFind(p, s, true)"></cfloop>

This doesn't work. Error: "Cannot convert the value of type class coldfusion.runtime.Struct to a boolean".

Similar to type 1. IMHO, Shouldn't it be anything but 0/false/undefined evaluates as if it were true?

This commonly works in other languages.

Another strike against the CF expression evaluator.

Type 4

<cfloop condition="((x = 1) and (x gt 0))"></cfloop

This doesn't work. Error: "Invalid CFML construct found on line 1 at column 5. ColdFusion was looking at the following text: ="

Similar to type 0.

<cfloop condition="x = 1 and x gt 0">

This doesn't work. Error. "Variable X is undefined."

Shouldn't x have been set by the first clause?

This commonly works in other languages. It's called precedence.

Another strike against the CF expression evaluator.

Type 5

<cfloop condition="((structKeyExists(url, ""x"")) and (x gt 0))"></cfloop>

This works great! Thanks CF team.

But how come precedence works for this type of expression, but not for assignment?

Thoughts?


Sep 24, 2009 at 1:26 PM // reply »
29 Comments

Shoot. Forgot to label Type 5. Type 6 is incorrectly labelled Type 5.


Sep 24, 2009 at 1:53 PM // reply »
11,314 Comments

@Alex,

I think what it comes down to is that the Condition value is evaluated as a ColdFusion expression (perhaps using the Evaluate() method or something similar). When it does that, it runs the code and then, I guess, uses the result as a Boolean.

Some of your Conditions throw errors because they are not valid ColdFusion statements. If you tried to run:

<cfscript> (x=0); </cfscript>

... as a standard CF statement, it would throw the same error - not valid syntax.

Also, because the condition needs to be evaluated as a Boolean, you have to get a full understanding of what is a "Truthy" value in ColdFusion, which is limited to non-zero numeric values (or things that can be implicitly converted to numbers), true keywords, and YES. Anything else probably cannot be converted to a boolean, which is why the reFind() that returns an array fails.


Sep 24, 2009 at 2:13 PM // reply »
29 Comments

@Ben,

> (x=0)
> not valid syntax

I understand.

Then expression syntax is different for assignment expressions than it is for comparison expressions.

Because these work fine:

assignment: <cfloop condition="x = 0"></cfloop>
comparison: <cfloop condition="(x eq 0)"></cfloop>
comparison: <cfloop condition="((x eq 0) or (x eq 1))"></cfloop>


Sep 24, 2009 at 2:17 PM // reply »
11,314 Comments

@Alex,

Yeah, exactly - some small differences. I actually prefer to use parenthesis around my conditions, so it's a shame that it throws an error :(


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Jun 18, 2013 at 9:20 PM
Mapping AngularJS Routes Onto URL Parameters And Client-Side Events
I couldn't find examples of passing multiple arguments using the when() routing statement so figured out through trial and error that you can pass multiple arguments using the following format: .whe ... read »
Jun 18, 2013 at 3:39 PM
Experimenting With The Amazon Simple Storage Service (S3) API Using ColdFusion
Hi Ben, THANKS! While not bleeding edge, it is new to me & I like learning new things every day! ... read »
Jun 18, 2013 at 12:30 PM
Disabling Auto-Correct And Auto-Capitalize Features On iPhone Inputs
Also spellcheck="false" should be mentioned as part of html5 specs ... read »
Jun 18, 2013 at 8:40 AM
Using Named Functions Within Self-Executing Function Blocks In Javascript
Hi Ben, you forgot to mention the most important thing for named self-executing functions - they can be referenced by name ONLY inside their execution context (which is parens in this case), it mean ... read »
dee
Jun 18, 2013 at 7:01 AM
My Safari Browser SQLite Database Hello World Example
hai ben, this program is really good i could understand the concept but i dint know how to save it and how to open it as you have done in the video can u give that details pls ... read »
Jun 18, 2013 at 6:04 AM
Clearing Inline CSS Properties With jQuery
Thanks a lot for for post! It helped me a lot... after being stuck since 24 hrs.. found solution from your post. Thanks again! ... read »
Jun 18, 2013 at 2:31 AM
SOTR 2013 - The Best Conference I Never Went To
I keep watching it, should keep me happily distracted until SotR14 ;) ... read »
Jun 17, 2013 at 9:45 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, As I was reading what you wrote, it occurred to me that maybe I do something similar to that in some of my client-side code. In an application I'm working on, there are a bunch of unrelated ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools