There are many ways to build a string in ColdFusion, but one often overlooked method involves using the <cfsavecontent> tag. This article will take a look at the standard ways that a ColdFusion developer might build a string, and compare it to using <cfsavecontent>.
In a ColdFusion application, you see this all the time:
<cfset MyString = "">
<cfset MyString = MyString & "This is the first line" & chr(10)>
<cfset MyString = MyString & "This is the second line" & chr(10)>
<cfset MyString = MyString & "This is the third line" & chr(10)>
The string is built up bit by bit, concatenated with new parts, and has a line feed at the end. It gets even more complicated when you have quotes in the line:
<cfset MyString = "">
<cfset MyString = MyString & "This is the ""first line""" & chr(10)>
<cfset MyString = MyString & "This is the ""second line""" & chr(10)>
<cfset MyString = MyString & "This is the ""third line""" & chr(10)>
Double quotes have to be escaped. It can get really messy when you have a lot of quotes in a string. You can get around this with single quotes:
<cfset MyString = "">
<cfset MyString = MyString & 'This is the "first line"' & chr(10)>
<cfset MyString = MyString & 'This is the "second line"' & chr(10)>
<cfset MyString = MyString & 'This is the "third line"' & chr(10)>
When putting a single quote around a string, you can freely use double quotes within, but you have to escape your single quotes then:
<cfset MyString = "">
<cfset MyString = MyString & 'This is Tom''s "first line"' & chr(10)>
<cfset MyString = MyString & 'This is Tom''s "second line"' & chr(10)>
<cfset MyString = MyString & 'This is Tom''s "third line"' & chr(10)>
The pound signs (#) allow you to use the variable inside the actual string, making concatenation even easier -- eliminating all the extraneous ampersands (&). Variables are replaced with the variable contents by the ColdFusion server:
<cfset MyString = "">
<cfset MyString = '#MyString#This is the "first line"#chr(10)#'>
<cfset MyString = '#MyString#This is the "second line"#chr(10)#'>
<cfset MyString = '#MyString#This is the "third line"#chr(10)#'>
This is much easier to write and easier to read than the previous statements, but there is still a better way.
The <cfsavecontent> tag is described like this in the ColdFusion documentation:
Saves the generated content of the cfsavecontent tag, including the results of evaluating expressions and executing custom tags, in the specified variable.
What that means is that everything that you put within the tag is saved into a variable that you specify. Let's look at the previous example using <cfsavecontent> instead of concatenation:
<cfsavecontent variable="MyString">
This is the "first line"
This is the "second line"
This is the "third line"
</cfsavecontent>
The most obvious advantage is that you can write your content as you want it to be presented, and have it saved into the variable for use wherever you need it. Another advantage is that you no longer have to escape any quote characters, or use ampersands or pound signs. This has tremendous advantages in situations where you are building the body of an email, content of a web page, or adding a JavaScript to a page.
The <cfsavecontent> tag also works with any dynamic content, such as the output of a query. You might have seen something like this before:
<cfquery name="rsOrder" datasource="#mydsn#">
SELECT o.*, od.*
FROM Orders o
INNER JOIN OrderDetails od
ON o.OrderID = od.OrderID
</cfquery>
<cfset orderTotal = 0>
<cfset OrderEmail = "Your order: " & chr(10) >
<cfset OrderEmail = OrderEmail & "Order Number: #rsOrder.OrderID#" & chr(10)>
<cfset OrderEmail = OrderEmail & "Ship To : #rsOrder.ShipName#" & chr(10)>
<cfset OrderEmail = OrderEmail & "--------------------------------" & chr(10) & chr(10)>
<cfoutput query="rsOrder">
<cfset OrderEmail = OrderEmail & "Product Name: #rsOrder.ProductName#: ">
<cfset OrderEmail = OrderEmail & "Price: $#rsOrder.ProductPrice# " & chr(10)>
<cfset orderTotal = orderTotal + rsOrder.ProductPrice>
</cfoutput>
<cfset OrderEmail = OrderEmail & "Total: " & orderTotal & chr(10)>
Now, write the same thing using <cfsavecontent>:
<cfquery name="rsOrder" datasource="#mydsn#">
SELECT o.*, od.*
FROM Orders o
INNER JOIN OrderDetails od
ON o.OrderID = od.OrderID
</cfquery>
<cfset orderTotal = 0>
<cfsavecontent variable="OrderEmail">
<cfoutput>Your order:
Order Number: #rsOrder.OrderID#
Ship To : #rsOrder.ShipName#</cfoutput>
--------------------------------
<cfoutput query="rsOrder">
Product Name: #rsOrder.ProductName#: Price: $#rsOrder.ProductPrice#
<cfset orderTotal = orderTotal + rsOrder.ProductPrice></cfoutput>
Total: <cfoutput>#orderTotal#</cfoutput>
</cfsavecontent>
Basically, you format the text so that it looks good, then simply wrap it with a <cfsavecontent>.
I frequently need a little JavaScript to go into the document head from within an include, but the include is often included in the body or somewhere else on the page. The <cfhtmlhead> tag lets you put content anywhere on the page, and CF will automatically put it in the head for you. This is great, but it breaks color coding in Dreamweaver and other editors and also has problems if you have multiple levels of quotes:
setInterval( "tfm_somefunction('" + className + "'," + red + "," + green + "," + blue + "," + speed + ")", 10 );
You would have to escape the quotes when using <cfhtmlhead>, and the coding can be confusing:
<cfhtmlhead text="<script type=""text/javascript"">
function blah(){
setInterval( ""tfm_somefunction('"" + className + ""',"" + red + "","" + green + "","" + blue + "","" + speed + "")"", 10 );
}
</script>">
Rather than go through the painful process of escaping quotes, use <cfsavecontent> and place everything into a variable:
<cfsavecontent variable="script">
<script type="text/javascript">
function blah(){
setInterval( "tfm_somefunction('" + className + "'," + red + "," + green + "," + blue + "," + speed + ")", 10 );
}
</script>
</cfsavecontent>
Then just use the variable in the <cfhtmlhead> tag:
<cfhtmlhead text="#script#">
Color coding now works for the JavaScript in Dreamweaver, and the script is put into the head when the page is passed to the browser. The other obvious advantage once again is that the script can be written normally and is readable.
The article has shown the advantages of using <cfsavecontent> when building strings for use in a ColdFusion page.