Although generating HTML in a CFC is not always good practice, when you have the choice between generating the HTML in a CFC or with jQuery it might be best to go with the CFC. The only reason I say this is for readability and updatability. But remember that it’s always best to create the HTML structure on the front-end page and fill in the data with Coldfusion or on the spot with jQuery and AJAX. So enough with the disclaimers.
Sometimes it is best to return a chunk of HTML to the browser built in a CFC. For example an application I’m working on at the moment consists of a nutritional label for a line of food products. I of course want the same label for each product, but with different data in each label. On top of this the label is used in several places in the application. To add one more layer of complexity, the application is very, very AJAX dependent. So the label is not only used in multiple places, but updates via an AJAX proxy to a CFC when the product changes. So in this case I opted to build my label with each call inside a <cfsavecontent> tag in a remote CFC.
When I began writing the application I was getting the data for the label via AJAX and returning it to some jQuery that used the html() method to write the html with the data returned from the CFC. It worked just fine like this. However, it didn’t take long for the client to want to make some very minor changes. Maybe it’s just me, but my html label in jQuery was not very readable or easy to update. At this point I moved the entire set of HTML to the CFC and just returned a save content variable to jQuery which output the label as a single prewritten chunk of code.
Once again this was just fine until I implemented the ability for the administrator to update the data in the label. Double-clicking a piece of the data in the label opened that data in a text field where the data could be manipulated and saved. The problem I found was that when the data became editable in the text area it was filled with a ton of white space around the data. So much so that the actual data could not even be seen in the text area without deleting a slew of white space. I went back and looked at the JSON that was returned and realized that all of my indentions and line breaks I created in the CFC for readability had carried over into the JSON. Of course, the browser ignores this white space so the label was showing correctly, but text fields do not ignore it.
So how do we remove this spacing and breaks so that it doesn’t show up in input fields and certainly not when saved to the database? As usual someone else out there has built a UDF to handle removing extra formatting. The UDF can be found at cflib.org under ‘HtmlCompressFormat(sInput)‘. It’s a fairly simple method, but from my use seems to work very well at removing extra formatting in HTML.
The method is written in script form, and since my CFC was working in tag form I quickly rewrote it to reflect a tag based structure. They work exactly the same and the tag based version below is simply a copy of the original script form. To use the UDF you just need to pass in the string to remove white space from. The method defaults to level 2 compression which I’ve found perfectly fine. But if you did want to more or less compression you can pass in a 1, 2, or 3 after the string.
Let’s look at an example. We have a save content variable in a cfc in which we write some nice readable indented HTML. Everything works fine when we output it in the browser. But if we load that HTML into a text area or rich text area we notice a whole lot of white space around the content. When we look at the JSON that is returned from the proxy call we notice a whole lot of ‘/t/t/t/t/t/t/t/n my content /t/t/t/t/t/t/t/t/n’ going on in the code. These are the formattings we need to get rid of. If this string is contained in a variable called ‘mystring’ we need to run this variable through the HtmlCompressFormat() method before inserting into a database or returning to the browser. So our method call would look something like
<!--- RUN STRING THROUGH COMPRESS HTML METHOD --->
<cfset compressedstring = HtmlCompressFormat(mystring, 2)>
So when writing dynamic HTML to be returned dynamically by jQuery I keep this method handy. Lastly, I’ll post the tag based copy of the method below. And if you want to see the original at cflib.org click here.
<cfcomponent displayname="Compress HTML" hint="Compresses any HTML passed in." output="false">
<!--- ***************************** COMPRESS HTML ***************************** --->
<cffunction name="compress" displayname="Compress HTML" description="Removes any extra whitespacing in HTML." access="public" output="false" returntype="String">
<!--- PASS IN HTML AND LEVEL OF COMPRESSION --->
<cfargument name="htmlString" displayName="HTML String" type="string" hint="String to be compressed." required="true" />
<cfargument name="level" displayName="Compression Level" type="numeric" hint="Level of compression" default="2" required="false" />
<cfset var stringToCompress = ARGUMENTS.htmlString>
<cfset var compressionLevel = ARGUMENTS.level>
<!--- TRIM OFF ANY EXTRA SPACES FROM STRING TO BE FILTERED --->
<cfset stringToCompress = trim(stringToCompress)>
<!--- RUN FILTER BASED ON SPECIFIED COMPRESSION LEVEL --->
<cfswitch expression="#compressionLevel#">
<cfcase value="3">
<cfset stringToCompress = reReplace(stringToCompress, "[[:space:]]{2,}", " ", "all")>
<cfset stringToCompress = replace(stringToCompress, "> <", "><", "all")>
<cfset stringToCompress = reReplace(stringToCompress, "<!--[^>]+>", "", "all")>
</cfcase>
<cfcase value="2">
<cfset stringToCompress = reReplace(stringToCompress, "[[:space:]]{2,}", chr( 13 ), "all")>
</cfcase>
<cfdefaultcase>
<cfset stringToCompress = reReplace(stringToCompress, "(" & chr( 10 ) & "|" & chr( 13 ) & ")+[[:space:]]{2,}", chr( 13 ), "all")>
</cfdefaultcase>
</cfswitch>
<!--- RETURN COMPRESSED HTML --->
<cfreturn stringToCompress>
</cffunction>
</cfcomponent>