Twitter: raymondcamden

Address: Lafayette, LA, USA

Making jQuery Mobile templates even easier - with ColdFusion

08-26-2011 14,057 views Mobile, jQuery, ColdFusion 7 Comments

Earlier today I read an interesting blog entry on jQuery Mobile and Rails. Now - let me start off with saying I'm not a huge fan of Ruby's syntax. I've got nothing against it and Rails. I did notice though that some of the template examples in the post seemed unnecessarily complex and verbose when it came to HTML. A few folks on Twitter informed me that was more his use of HAML than Ruby. Fair enough. That being said, the author did some very interesting things with his templates and I thought I'd work on a ColdFusion version. Credit for the coolness though goes squarely to the original author, Ken Collins.

So - creating a ColdFusion custom tag to handle layouts is not something new. You've been able to build custom tag wrappers since version 4, approximately 200 years ago. But if you look at Ken's code, even if you can't read the Ruby/HAML, you will see two very cool things he is doing with his templates. First - he is simplifying the creation of page IDs. jQuery Mobile requires your pages to use unique IDs. His template makes that automatic. I decided for my code I'd make it automatic, but let you supply one if you wanted. Secondly - jQuery Mobile pages loaded after the initial request do not need to return the entire HTML block. Ie the HTML tag, BODY, etc. His code intelligently checks for Ajax requests and minimizes what is returned when it can. That quick little tweak will add just a bit more speed to your pages and is easy enough to add in our code as well. Here's my first custom tag, page.cfm.

view plain print about
1<!--- Courtesy Dan Switzer, II: --->
2<cffunction name="isAjaxRequest" output="false" returntype="boolean" access="public">
3 <cfset var headers = getHttpRequestData().headers />
4 <cfreturn structKeyExists(headers, "X-Requested-With") and (headers["X-Requested-With"] eq "XMLHttpRequest") />
7<cfif thisTag.executionMode is "start">
9    <cfparam name="attributes.title" default="">
10    <cfparam name="attributes.customscript" default="">
11    <cfif not structKeyExists(attributes, "pageid")>
12        <!--- Make a page based on request. --->
13        <cfset attributes.pageid = replace(cgi.script_name, "/","_","all")>
14    </cfif>
15    <cfparam name="attributes.theme" default="">
17    <cfif not isAjaxRequest()>
18    <!DOCTYPE html>
19    <html>
21    <head>
22        <meta charset="utf-8">
23        <meta name="viewport" content="width=device-width, initial-scale=1">
24        <cfoutput>
25        <title>#attributes.title#</title>
26        <link rel="stylesheet" href="" />
27        <script src=""></script>
28        <cfif len(attributes.customscript)>
29            <srcript src="#attributes.customscript#"></script>
30        </cfif>
31        </cfoutput>
32        <script src=""></script>
33    </head>
35    <body>
37    </cfif>
39    <cfoutput><div data-role="page" id="#attributes.pageid#" data-title="#attributes.title#" <cfif len(attributes.theme)>data-theme="#attributes.theme#"</cfif>></cfoutput>
43    </div>
45    <cfif not isAjaxRequest()>
46    </body>
47    </html>
48    </cfif>

For the most part I'm going to assume this is easy enough to read. If you've never seen a custom tag "wrapper" before, check out this blog entry I wrote back in 2007. Basically ColdFusion passes to your custom tag whether or not the execution is at the beginning or end of the tag. Notice the check for the pageid value. If it doesn't exist, we create it based on the request path. Again, this is based on Ken's template. The other interesting part is the isAjaxRequest UDF. It's taken from code Dan Switzer wrote (and something I blogged about in the past as well). If we detect an Ajax request, we will suppress everything but the code div. Finally - I added support for passing in the URL to a custom script and a theme selection as well. Here's an example of how you could call this:

view plain print about
1<cf_page title="Home Page">

Or you can use cfimport:

view plain print about
1<cfimport prefix="jqm" taglib="jqm">
3<jqm:page title="Home Page">

Next up - I decided to quickly add support for 3 main jQuery Mobile UI items - header, footer, and content. This allows me to complete a page like so:

view plain print about
1<cfimport prefix="jqm" taglib="jqm">
3<jqm:page title="Home Page">
5    <jqm:header>Welcome!</jqm:header>
7    <jqm:content>
8        This is my main page content. Go to <a href="test2.cfm">next</a>.
9    </jqm:content>
11    <jqm:footer>Copyright &copy; 2014</jqm:footer>

Each of these three new tags are the exact same, so I'll share one of them here (content.cfm):

view plain print about
1<cfif thisTag.executionMode is "start">
2    <cfparam name="attributes.theme" default="">
4    <div data-role="content" <cfif len(attributes.theme)>data-theme="#attributes.theme#"</cfif>>
8    </div>

And here is another example:

view plain print about
1<cfimport prefix="jqm" taglib="jqm">
3<jqm:page title="Home Page" id="page2" theme="e">
5    <jqm:header>Welcome!</jqm:header>
7    <jqm:content>
8        This is my second page content. Go to <a href="index.cfm">home</a>.
9    </jqm:content>
11    <jqm:footer theme="b">Copyright &copy; 2014</jqm:footer>

By the way, I'm not normally a cfimport fan myself. I use it every now and then when the mood hits me. If it scares you, here's the above example with just cf_ syntax.

view plain print about
1<cf_page title="Home Page" id="page2" theme="e">
3    <cf_header>Welcome!</cf_header>
5    <cf_content>
6        This is my second page content. Go to <a href="index.cfm">home</a>.
7    </cf_content>
9    <cf_footer theme="b">Copyright &copy; 2014</cf_footer>

I did some quick testing with my Chrome Net panel open, and can confirm that when I requested my second page (and clicked the link back home), the template correctly noted it as an Ajax request and suppressed the unnecessary HTML. If you want to play with these custom tags I've included them as a zip to this blog entry.

Download attached file


These comments will soon be imported into Disqus. To add a comment, use Disqus above.
  • John Farrar #
    Commented on 08-26-2011 at 1:10 PM
    Sweet, nice to see more Custom Tag content used where it should be. There was a day we missed the target and used them too much. This is a great use case of the right way to do it and a great blog post. Keep up the awesomeness Ray!
  • Commented on 08-26-2011 at 1:27 PM
    I love it! Can't make a page creation any easier than that :)
  • Connor Middleton #
    Commented on 08-26-2011 at 3:12 PM
    This is pretty sweet Ray. I'll probably put this to use on a project I am just spooling up. Thanks
  • Commented on 08-26-2011 at 3:26 PM
    Interesting take, and cool routine. Thanks!
  • Commented on 08-26-2011 at 8:43 PM
    What could be next? A Dreamweaver template? Just kidding.
  • Misty #
    Commented on 01-31-2012 at 1:41 AM
    Hi ray, Good post.

    My Question here is

    1. Can I cfinclude the templates in the pages - i think i can
    2. Is the new way to write jquery mobile applications pertaining to their own attaibute usage like ui-hidden-theme classes or data-role="something"

    3. silly question but let me ask - can i add my application.cfm or application.cfc - i think i can
  • Commented on 01-31-2012 at 6:35 AM
    1) Um, well yeah, thats kinda the point. ;) You aren't cfincluding it though, you are using it as a custom tag.

    2) No idea at all what you mean here.

    3) Yes.