Rob asks:
Is there a <cfhtmlfoot> tag? One that would write at the end of html file, before </body> tag...
In case folks don't get why he is asking, ColdFusion comes with a cfhtmlhead tag that lets you dynamically add stuff to the HEAD portion of an HTML document. There is not a corresponding tag like what Rob wants, but there is no reason we can't hack one up in a custom tag. My solution will make use of both the Request scope and the oft-maligned (by me) onRequest function. First, a sample page:
<cf_htmlfoot text="<p>© Raymond Camden #year(now())#">
<html>
<head>
<title>Test</title>
</head>
<body>
<p>
Woohoo,web design kicks butt.
</p>
</body>
</html>
This is a trivial page with simple text on it. Note the call to the custom tag, htmlfoot, on top. The custom tag just does this:
<!--- the text to add --->
<cfparam name="attributes.text" default="">
<!--- where we store it --->
<cfparam name="request.footertext" default="">
<!--- add it --->
<cfset request.footertext &= attributes.text>
As you can see, we simply take your text, and append it to the text we want to add to the foot. This actually makes my tag better as I don't think you can have multiple cfhtmlhead tags. If I weren't so lazy, I'd also make the custom tag support this syntax:
<cf_htmlfoot>
Foo Foo
</cf_htmlfoot>
Anyway, the last step is to enable onRequest to notice the Request scope variable we created:
<cffunction name="onRequest" returnType="void">
<cfargument name="thePage" type="string" required="true">
<cfset var content = "">
<cfsavecontent variable="content">
<cfinclude template="#arguments.thePage#">
</cfsavecontent>
<cfif structKeyExists(request, "footertext")>
<cfset content = replacenocase(content, "</body>", "#request.footertext#</body>")>
</cfif>
<cfoutput>#content#</cfoutput>
</cffunction>
There isn't much to talk about here. All I did was look for the Request variable, and if it existed, I insert it into the result HTML before outputting it to the browser. Again, I'm not a big fan of onRequest, but this is an interesting example of how one could use it.
Archived Comments
If you are going to go with the trouble of making a custom tag, and making it really complex to handle more than just text, why not just use a cfinclude on each page before the body? that way it could embed a much richer and simpler code separeted in .cfm files.
Unless code reuse is DEEPLY related here, I dont see why doing this would be good. Maybe because cfhtmlhead doesnt make that much sense either for me :(
How dare you say my waste of time is a waste of time. I am highly offended!
cfhtmlhead isn't a waste of time and I can certainly see some usage for cfhtmlfoot. I recently came across the benefits of cfhtmlhead and it's not really useful until you think "man, I wish I could shove this javascript/metadata up into the header of my templates without actually having to write it there."
Then the little lightbulb comes on.
cfhtmlhead is very useful.
sure you don't HAVE to have your javascript in the head tag but I like it there, its neater.
And if you use a MVC framework you don't typically have access to the htmlhead so if you do want to jam some javascript, css or metadata tags into the head of the page from your display page you need to use it.
Then again if you are using an MVC framework you could declare two variables htmlhead and htmlfoot and output them in the appropriate places in your layoutpage, then you simply need to set those variables with whatever it is you want to output when you want stuff jammed in the header or footer....no need to create a custom tag to do it, no need to use onRequestEnd.
What happened to OnRequestEnd.cfm?
Technically that isn't a suitable answer. Sure you can use it to append stuff at the end, but in this question, the idea is - I've got a full layout already but I want to insert something before the body tag.
okay, what about..
at the end of the specific page
<cfset somevariable = "html goes here">
and in the OnRequestEnd.cfm
<cfif IsDefined("somevariable")>#somevariable#</cfif>
and then the rest of the "footer" layout follows.
if the html is complex, maybe use cfsavecontent?
My code is brief, probably needs some better coding.
Tell me what you think?
While that does work, it doesn't technically apply to the problem at hand in this blog post - which is to dynamically insert something before the body tag. I'm splitting hairs here probably. ;)
no problem. I have learnt a lot from you. Just wanted your opinion on my method.
Thanks Ray.
Well, if we agree that what you want isn't the best specifically for what we discuss here, let me comment in general.
I don't think onRequestEnd is a good way to do layout stuff. Nor would I recommend Application.cfm. Nor onRequestStart/End.
I recommend using custom tags for layout. So my page would look like so:
<cf_layout title="foo">
some page
</cf_layout>
I've got a blog entry on it here on the blog somwhere.
The reason I don't like using app.cfm/onrequestend.cfm/app.cfc is that if you have a page that DOESN'T need layout, like a popup window, then you have to embed code in those files to block it. To me, this should be done on the page instead.
ok, i'm an old school cfer. I learnt from CF5. I have all my page headers, menus and footer drawn from application.cfm and onrequestend.cfm. These pages have cfincludes to draw in headers, menus and footers. When i need a page, like a popup, i call the page with a url variable something like popup.cfm?noheaders.
The application.cfm looks for this and does not include "header.cfm", "menu.cfm", etc. The same for OnRequestEnd.
I've always had a gut feeling that this is wrong. I will look into it when I have some time. Unfortunately my current client wants results now, so I have to code as I know how to code.
Hi Ray,
I'm puzzled by something. I have an old FB3 app where I use CFHTMLHEAD. But everything I put in the tag comes TWICE in the <head>-tag. Any ideas to why? It doesn't change if I put the tag in the dsp-file, the fbx_switch.cfm or in the layout_nnn.cfm file. HELP!!!
If you add a cflog before the cfhtmlhead, do you see 2 log messages per request?
We had the same problem described by Sebastiaan. We had a template running getPageContext().getOut().clearBuffer(); so we could manipulate the HTML to perform actions such as removal of whitespace. We were also seeing duplicate output from CFhtmlhead and CF generated Javascript. Removing this call fixed the issue for us.
I know this is an old thread, but I came across it while looking for common methods of achieving a "reverse" <cfhtmlhead> tag. Personally, I'd love to see a <cfhtmlfoot> tag. Most of my interface work is done with JavaScript, and for performance reasons, it is often best to load it at the end of the page just before the </body> tag. Or so says the pag speed utility in Firebug :-) Of course I've worked around this with a method similar to those listed above, but it would be nice to have native language support for something like that for the sheer purpose of standardizing the code for other developers. Despite the fact this is a simple custom tag, it can always be scary when look at a code base and see a bunch of unknown custom tags.