Inlining AngularJS Templates Using ColdFusion

Posted October 5, 2012 at 4:39 PM by Ben Nadel

Tags: ColdFusion, Javascript / DHTML

In an AngularJS application, you're probably going to make heavy use of templates; or "views" or "partials" or whatever you want to call the snippets of HTML that you bring together in order to construct your user interface. In AngularJS, templates can be loaded using the ngView or ngInclude directives. In either case, the template is defined as a filepath, relative to the currently executing page. If the given view has not yet been loaded, including it will precipitate an HTTP request such that AngularJS can load, compile, and cache it. If, however, you don't want to incur the cost of the network connection, AngularJS allows you to inline your views using Script tags.


 
 
 

 
  
 
 
 

When making a request for a template, AngularJS will look at the Script tags on the page before initiating a network connection. Specifically, it will look for Script tags in the following format:

  • <script type="text/ng-template" id="your/view/file/path.htm">
  •  
  • ... view content goes here ...
  •  
  • </script>

Notice that the Script tag type is "text/ng-template" and that the "id" of the tag is the same as the relative file path to your template. If AngularJS can find the Script tag with the matching ID, it will compile and cache the tag content rather than trying to load the template over the network connection.

This is pretty sweet! And, if you're using a server-side language like ColdFusion, front-loading your templates is extremely easy. All you have to do is read in your directory structure and write it out to inline Script tags.

To demonstrate this, I have put together a simple AngularJS routing demo:

  • <!doctype html>
  • <html ng-app="Demo">
  • <head>
  • <meta charset="utf-8" />
  • <title>Inlining AngularJS Templates Using ColdFusion</title>
  • </head>
  • <body>
  •  
  • <h1>
  • Inlining AngularJS Templates Using ColdFusion
  • </h1>
  •  
  • <p>
  • <a href="#/home">Home</a> -
  • <a href="#/blog">Blog</a> -
  • <a href="#/contact">Contact</a>
  • </p>
  •  
  • <div ng-view>
  • <!--
  • The ngView directive will render the content templates
  • based on the route configuration.
  • -->
  • </div>
  •  
  •  
  • <!--- Inline the "views" directory. --->
  • <cfinclude template="inline_views.cfm" />
  •  
  •  
  • <!-- Load AngularJS from the CDN. -->
  • <script
  • type="text/javascript"
  • src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js">
  • </script>
  • <script type="text/javascript">
  •  
  •  
  • // Create an application module for our demo.
  • var Demo = angular.module( "Demo", [] );
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // Configure the application routes.
  • Demo.config(
  • function( $routeProvider ) {
  •  
  • // Map the routes to the HTML templates.
  • $routeProvider
  • .when(
  • "/home",
  • {
  • templateUrl: "views/home.htm"
  • }
  • )
  • .when(
  • "/blog",
  • {
  • templateUrl: "views/blog.htm"
  • }
  • )
  • .when(
  • "/contact",
  • {
  • templateUrl: "views/contact.htm"
  • }
  • )
  • .otherwise(
  • {
  • redirectTo: "/home"
  • }
  • )
  • ;
  •  
  • }
  • );
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • </script>
  •  
  • </body>
  • </html>

As you can see, this routing example makes use of three different templates:

  • views/home.htm
  • views/blog.htm
  • views/contact.htm

Normally, requesting the corresponding routes would require an HTTP connection in order to load and render the templates. But, our "inline_views.cfm" ColdFusion server-side script removes this requirement by inlining the templates into the main page as Script tags:

inline_views.cfm

  • <cfoutput>
  •  
  • <!---
  • Recursively gather all of the htm file paths from the view
  • directory. By using the "paths" argument, the return value
  • will be an array (as opposed to a query) and will only
  • contain the file paths.
  • --->
  • <cfset filePaths = directoryList(
  • expandPath( "./views/" ),
  • true,
  • "paths",
  • "*.htm"
  • ) />
  •  
  • <!---
  • The filePaths will be returned with fully-expanded file paths.
  • Since our AngularJS application is executing relative to the
  • "web app" folder, we'll need to create app-local file paths.
  • --->
  • <cfset appDirectory = getDirectoryFromPath( expandPath( "./" ) ) />
  •  
  •  
  • <!---
  • As we inline the AngularJS view templates, let's store the
  • output in an intermediary buffer so we have the change to
  • minimize the markup.
  • --->
  • <cfsavecontent variable="scriptBuffer">
  •  
  • <!--- Include each view as an inline Angular script. --->
  • <cfloop index="filePath" array="#filePaths#">
  •  
  • <!---
  • Chop of the pre-app file path in order to get a file
  • path that AngularJS will be able to find.
  • --->
  • <cfset relativeViewPath = replace(
  • filePath,
  • appDirectory,
  • ""
  • ) />
  •  
  • <!---
  • If we create an ng-template element with an ID that
  • matches the relative file path, AngularJS will
  • compile it and add it to the template cache without
  • making an HTTP request.
  • --->
  • <script type="text/ng-template" id="#relativeViewPath#">
  • <cfinclude template="#relativeViewPath#" />
  • </script>
  •  
  • </cfloop>
  •  
  • </cfsavecontent>
  •  
  •  
  • <!---
  • Strip out all leading / trailing white space per line. This
  • should safely strip out whitespace that we don't need (while
  • leaving other meaningful whitespace in place.
  • --->
  • #reReplace( scriptBuffer, "(?m)^\s+|[ \t]+$", "", "all" )#
  •  
  • </cfoutput>

As you can see, this converts each template to a "text/ng-template" Script. Now, when I navigate around the routes of my AngularJS application, no subsequent HTTP requests to the server need to be made. Of course, whether or not you actually want to front-load your templates is going to depend on your particular situation.




Reader Comments

There are no comments posted for this web log entry.

Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 23, 2013 at 9:52 PM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Muhmmadibn Did you figure out a solution to launching PDFs? I am running into the same issues myself. There is no way to close the PDF or go back once you launch it. Thanks in advance! ... read »
May 23, 2013 at 6:06 PM
The Girl Who Broke My Heart, And Made Me A Better Person
Good day,ladies and gentle men, my name is Dr AMADI the great spell caster in Africa, i have help so many people for different kind of problems,who say there is no solution to problems on earth, that ... read »
May 23, 2013 at 4:26 PM
ColdFusion QueryAppend( qOne, qTwo )
@Heather, Glad people are still getting value out of this! ... read »
May 23, 2013 at 3:49 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, I meant the code at the bottom (not the video). I did try to experiment with an intermediary variable, like: value = users.id[ i ]; arrayContains( userIDs, value ); ... but t ... read »
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
May 23, 2013 at 9:55 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dan, According to the CF Admin, I'm running Java "1.6.0_45". As far as the DB column, in the database it's an INT. I'll see if I can dig into what CF sees it as. @WebManWalking, But h ... read »
May 23, 2013 at 9:49 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, I think the problem is that we're used to loose typing in ColdFusion, like JavaScript. If a value is a number but it's needed in an expression to be a string, noooo problem. I've encountered ... read »
May 23, 2013 at 9:47 AM
ColdFusion QueryAppend( qOne, qTwo )
You rock! Thank you, thank you, thank you!!! ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools