Ok, now that you've all downloaded 8.0.1 (in the last 5 minutes) and had a chance to play with it, I'm going to do a few blog entries about some of the new features in 8.0.1. ColdFusion 8 added the ability to use attributeCollection to ColdFusion built in tags. In case you never played with that feature (it's been around for a while in custom tags and cfinvoke), it allows you to dynamic define attributes for a tag. Consider:
<cfset s = structNew()>
<cfset s.file = expandPath("./test.cfm")>
<cfset s.action = "read">
<cfset s.variable = "r">
<cffile attributeCollection="#s#">
<cfoutput>#htmlCodeFormat(r)#</cfoutput>
This can be useful when you have to do different types of operations based on your business logic. It can save you from writing a lot of CFIF statements. For example, consider cfmail. You could dynamically add security attributes (for the server) instead of having to provide it in the core tag.
Ok - so that's ColdFusion 8. CF 8.0.1 expands on this by allowing you to add any attribute. So for example:
<cfset s = structNew()>
<cfset s.file = expandPath("./test.cfm")>
<cfset s.action = "read">
<cfset s.variable = "r">
<cfset s.frankie = "goestohollywood">
<cffile attributeCollection="#s#">
<cfoutput>#htmlCodeFormat(r)#</cfoutput>
Obviously frankie is not a valid attribute to cffile, but in 8.0.1, this will be ignored when passed through attributeCollection. You can disable this in the ColdFusion Admini, or in Application.cfc, and even in the structure itself.
So why would you do this? You may have common attributes that you want to share in a structure and pass to multiple tags.
Now I have to admit - when I first heard of this feature, I fought against it. I thought it was a bad idea. I was overruled (in a big way ;) so I'm curious to see what others think. I'm definitely more open to it now - but while I've used attributeCollection in the past, I haven't used it much at all yet in core CF tags, so this isn't a big deal to me now.
Anyone planning on using this?
Archived Comments
I'll definetely keep this in mind now that it's available. I love the ability to configure custom params but only have one call of the actual CF tag. Before it was a case of either having a default variable set or lots of silly CFIF's and multiple tag calls.
I use attributeCollection quite a lot in my Services and Gateways so this will fit nicely into the arsenal of code options. Quite a flexible little feature.
Apparently, don't see any use of custom attribute for me. But Ray, thanks for noticing me the ability to use attributeCollection to ColdFusion built-in tags which was unknown to me.
I can't think of any use cases off the top of my head. The original feature is great, since sometimes you don't know in advance if a particular attribute will be needed, which, as James and yourself have pointed out, can result in some silly IF statements.
Being able to pass in arbitrary attributes strikes me as a bit dangerous though. For example I always misspell variable 'varaible' when I type - and when I do it is nice to know that I did!
Can you specify an attribute AND include an argumentCollection struct? If so, if you repeat an argument name, which takes precedence?
I am subscribing to see if anyone comes up with any interesting use cases.
@Ben- No, unlike custom tags, it has to be all or nothing (afaik, haven't had coffee yet).
You CAN specify a collection and an Attribute and the attribute on the tag wins! :)
So...
<cfset myquerysettings.datasource= "MyMySQLDB"/>
<cfset myquerysettings.username = "foo"/>
<cfset myquerysettings.password= "bar"/>
<cfset myquerysettings.mypersonalattribute= "I like MySQL"/>
<cfquery attributeCollection="MyMySQLDB" password="password2">
Select * from users
</cfquery>
I have been the big proponent of this little feature because it allows CF tags to behave like UDFs (you can pass in extra stuff and those "just work" too).
So, what's another use case?
<cffunction name="cfmail">
<cfmail attributeCollection="#arguments#">
#arguments.body#
</cfmail>
</cffunction>
<cfscript>
mailparams.to = "foo@bar.com";
mailparams.from = "baz@foo.org";
mailparams.subject = "cfmail in cfscript";
mailparams.body = "You can create UDFs for tags that are forward compatible!"
</cfscript>
There are a bunch of other useful use case... creating defaults for tags in your application, storing metadata in objects and passing the entire object to a various tags... etc.
My main thing is that I wanted it to work like a user defined function, which allows extra stuff too. :)
Note: if you just use the attributes, these are still all validated for typos, so if you're worried about fat fingering... don't use this. :)
Let us know if you run into other cool uses!
Jason
Oh... I forgot..
<cfscript>
cfmail(mailparams);
</cfscript>
Not bad huh? :)
Jason
Jason - I forget. Was the ability to mix both inline and attributeCollection added in 801? I know the 'any arg you want' was added, but specifically the mix.
Having both the collection and a tag attribute, mix-n-match if you prefer :), was added with 8.0.1.
:)
Jason
@Jason
You Wrote:
-----------------
Oh... I forgot..
<cfscript>
cfmail(mailparams);
</cfscript>
-----------------
We can *call* tags like a UDF? (!?!?!)
Any tag?
That can't be right... can it?
!!!
Nope. You would have to write a tag for it. But your udf would be very simple.
<cffunction name="cfmail">
<cfmail attributeCollection=arguments>
</cffunction>
Ah I See. I nearly fell off my chair then.
Hey Ray, I am using this in my one of the custom tags and i am passing the value from the calling template as:
<cf_call mailing="{to='i@i.com',server='this.thisdomaijn.com',type='html',from='me@me.com'}">
now in my call.cfm custm tag i am using it like this
<cfmail attributecollection = "#attributes.call#">
it is giving me this error
The attributeCollection attribute in the cfmail tag can only be a structure.
I am getting this Error:
The attributeCollection attribute in the cfmail tag can only be a structure.
<cf_call ckmail="{to='test@test.com',from='test@test.com',subject='Error reported',mailserver='mail.domain.com',username='1234',password='tested'}">
in the custom tag call.cfm i have the following
<cfmail attributecollection = "#attributes.ckmail#">
You passed a string. To make that 'real' CF variable, try wrapping the {} with #.
i did not get it, can you please write the example as of how we are saying it to be done!
Instead of foo="{....}" do foo="#{...}#"
ok, now that did resolved but now mails are not coming
Um - but how am I supposed to know? You are using a custom tag called "call" - I have no idea what that is.
Oh sorry - I see where you say you use cfmail. Best thing to do is check your CF mail logs.
ok, i got it, i checked it in logs, mail is there, might be some server authentication issue, the issue is now resolved, Thanks Ray as always
Ok, now here is the question, tested on CF9 and it worked, Now Testing on CF 8.0.1, It failed miserably
<cf_call ckmail="#{to='test@test.com',from='test@test.com',subject='Error reported',mailserver='mail.domain.com',username='1234',password='tested'}#">
in the custom tag call.cfm i have the following
<cfparam name="attributes.ckmail" default="">
<cfmail attributecollection = "#attributes.ckmail#">
Error I am getting
Invalid CFML construct found on line 11 at column 18.
ColdFusion was looking at the following text:
{
You can't use that syntax in that way in CF8. Simply make a structure the 'old' way and pass it.