Tip: cfsavecontent and cfinclude within script based CFCs

Ok, so I know that I've said (many times) that including layout in a CFC is generally a bad idea. I still think it is. But like most rules there are always exceptions. Normally this wouldn't be a big deal, but HTML and JavaScript within a script based component is - well - it's ugly. Here is an example:

case "textbox": { return s & '<input type="text" name="#arguments.name#" value="#currentValue#">'; }

This simple example works, but more complex HTML gets messier. I could have switched the component over to tags. It's not like that would be the end of the world! But then I remember - you can use savecontent within script based cfcs. So instead of the inline HTML you see above, I now use:

case "event date": { savecontent variable="s" { include "render/eventdate.cfm"; } return s; }

Woot. I wish I had remembered this when I began the project, but I'm guessing I'll be getting used to ColdFusion 9 syntax until right around the release of ColdFusion 10.

Archived Comments

Comment 1 by Daniel Budde posted on 12/23/2009 at 7:09 PM

Although, I am not on CF9 yet, I have ran into this in the past when I wanted to e-mail template based reports from within my CFC. The reports already existed as HTML templates within the application, so the easy fix was to use <cfsavecontent> with a <cfinclude>.

It always makes me feel a little bad to have to break encapsulation, but as you say, there are those exceptions to the rule. I always just comment them well and since they are few and far between, they have just never caused any trouble.

Comment 2 by Tony Nelson posted on 12/23/2009 at 8:34 PM

You'll want to be careful when using .cfm mixins inside singleton components to make sure any variables declared within the mixin are thread-safe.

Comment 3 by Raymond Camden posted on 12/23/2009 at 8:54 PM

Agreed. I'm forcing myself to use local.x for all variables. I normally do NOT like local.foo, I just var scope, but for this component I'm using it as a way to ensure I'm always local.

Comment 4 by Daniel Budde posted on 12/23/2009 at 8:59 PM

I do the same as well. All my variables used within the template are always located under (LOCAL.templateInfo).

Comment 5 by Tony Nelson posted on 12/23/2009 at 9:31 PM

If you don't want to have to use local.x everywhere, you could create a small Include.cfc proxy for including templates.

case "event date": {
return new Include("render/eventdate.cfm",arguments);
}

Include.cfc:
component {
public string function init(template, params) {
structDelete(variables, "init");
structDelete(variables, "this");
structAppend(variables, arguments.params);
savecontent variable="local.html" {
include arguments.template;
}
return local.html;
}
}

Now any variables declared inside render/eventdate.cfm won't bleed into your component.

Comment 6 by Raymond Camden posted on 12/23/2009 at 9:32 PM

That's slick as crap. Thanks Tony.