Skip to main content
Ben Nadel at CF Summit West 2024 (Las Vegas) with: Sam Effa
Ben Nadel at CF Summit West 2024 (Las Vegas) with: Sam Effa

Struct Iteration With CFLoop Exposes Both Key And Value In Lucee CFML 5.3.6.61

By
Published in Comments (5)

Back in February, when I was having lunch with Gert Franz, co-creator of Lucee CFML, we were commiserating on how amazing ColdFusion is. At that lunch, Gert told me about some of the great things that Lucee CFML offers, like its seamless support for ColdFusion Tags in CFScript. Another minor feature that he mentioned was that the CFLoop tag exposes both Key and Value attribute that remove the need to look-up the value within the CFLoop body. Now, months later, I finally used this feature for the first time in yesterday's post on proxying Amazon S3 uploads using CFHTTP and Lucee CFML. Given the fact that Adobe ColdFusion doesn't support this feature, I thought it might be worth exploring in Lucee CFML 5.3.6.61 in case new Lucee-converts didn't realize it was there (just as I didn't).

To paint this historical picture of what looping over a Struct in Adobe ColdFusion would look like, I am sure this type of code is near-and-dear to many developer's hearts:

<cfset data = {
	hello: "world",
	foo: "bar",
	missing: javaCast( "null", "" ),
	cool: "beans"
} />

<!---
	When looping over a Struct with the CFLoop tag in Adobe ColdFusion, we only have the
	Item attribute, which gives us the key in the iteration. Once inside the iteration,
	we have to look up the Value for ourselves (assuming the key exists).
--->
<cfloop collection="#data#" item="key">

	<cfif structKeyExists( data, key )>

		<!--- We have manually extract the value from the Struct. --->
		<cfset value = data[ key ] />
		<cfset writeOutput( key & " : " & value & "<br />" ) />

	<cfelse>

		<cfset writeOutput( key & " : [undefined] <br />" ) />

	</cfif>

</cfloop>

As you can see, within the CFLoop tag, all we have access to on the Struct is the item, which exposes the iteration key. With that key, we then have to manually extract the value from the Struct as we perform the iteration.

With the CFLoop tag in Lucee CFML, we can leverage both the item and the index attributes in order to access both the value and the key, respectively:

<cfscript>

	data = [
		hello: "world",
		foo: "bar",
		missing: nullValue(),
		cool: "beans"
	];

	// In Lucee CFML (not currently supported in Adobe ColdFusion), when you iterate over
	// a Struct using the CFLoop tag, you can provide BOTH an INDEX and an ITEM attribute
	// which grant you access to both the Key (index) and the Value (item).
	loop
		collection = data
		index = "key"
		item = "value"
		{

		echo( key & " : " & ( value ?: "[undefined]" ) & "<br />" );

	}

	echo( "<br />" );

	// Of course, if you were to use Function-based iteration, you can also access both
	// the Key and the Value as arguments on the iteration operator.
	data.each(
		( key2, value2 ) => {

			echo( key2 & " : " & ( value2 ?: "[undefined]" ) & "<br />" );

		}
	);

</cfscript>

As you can see, in our CFLoop tag, we're mapping the index to the key and the item to the value. And, when we run this code, we get the following browser output:

hello : world
foo : bar
missing : [undefined]
cool : beans

hello : world
foo : bar
missing : [undefined]
cool : beans

Awesome! As you can see, we get declarative access to both the key and value during Struct iteration - no need to imperatively access any data.

And, for funzies, I also threw in the .each() approach as well in order to demonstrate that function-based traversal also exposes both the key and the value.

This may seem like a tiny little feature; and, it totally is. But, part of what makes Lucee CFML such a joy to work with is that is jam-packed with tiny little features like this one.

Want to use code from this post? Check out the license.

Reader Comments

15,902 Comments

@Zac,

I am just amazed how fast you all update stuff. I feel so fortunate to be part of such a proactive community. The behavior is a little funny with the optional argument. The truth is, in 99.99% of cases, I iterate over Structs using a simple for-in loop. And the reality is, I almost never need to iterate over Structs. But, once in a blue-moon I due, and it's nice to know this is a feature I can leverage.

15,902 Comments

@All,

In this post, you may notice that the second example with .each() is using differently-named arguments. This is for a reason - if I were to use key and value in the .each() version, I would have gotten an "unexpected" outcome because of the scope cascade in ColdFusion. Since this is a fun little behavior, I thought I would call it out specifically:

www.bennadel.com/blog/3852-scope-traversal-behavior-with-undefined-function-arguments-in-lucee-cfml-5-3-6-61.htm

58 Comments

Thanks Ben, back at ya!

As senior devs, it's always fun to fix / improve things as we have the knowledge to do it, hopefully making the lives of other cfml developers easier!

I've been working on and with Lucee for a years now, it's great that you're also involved and sharing your love for cfml with Lucee via your blog posts!

Thanks for the fresh inspiration to improve things with each post :)

15,902 Comments

@All,

So, I was just reading through the Lucee CFML docs earlier this week (as one does), and I realized that CFLoop is even cooler than I thought it was. I don't know when this was introduced, but apparently you can even use key, value, and struct aliases during Struct-iteration:

www.bennadel.com/blog/3916-struct-iteration-with-cfloop-includes-super-intuitive-aliases-in-lucee-cfml-5-3-6-61.htm

This language, man -- just keeps getting more awesome!

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel