Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at the jQuery Conference 2010 (Boston, MA) with:

Inlining AngularJS Templates Using ColdFusion

By Ben Nadel on

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.

Tweet This Great article by @BenNadel - Inlining AngularJS Templates Using ColdFusion Thanks my man — you rock the party that rocks the body!



Reader Comments

Thanks for a wonderful demo. I'm just getting started with AngularJS.

If anyone is developing on Windows boxes, you may need an additional bit of code at line 43 in inline_views.cfm.

  • <!---
  • This will handle conversion of Windows style directory separators.
  • --->
  • <cfset relativeViewPath = replace(relativeViewPath, "\", "/", "all") />

Reply to this Comment

by any chance do you have any series of posts on AngularJS? I am just getting started on it and there seems to not too much documentation around :(
Your blog is easy to understand conceptually, linguistically and examples. So think it would be the first place I ask before I go other places :)

Reply to this Comment

@Joe,

Ah, good call. I can never remember which parts of the pathing is system-agnostic. I know you can do some things without problems.

@Dinesh,

I'm really glad you're liking the posts. I do have a LOT of posts about AngularJS; unfortunately, they are not super easy to find since my tagging on the site is not very good at this time. The easiest thing might be to just look at my list of JavaScript blog posts and read through the names:

http://www.bennadel.com/blog/tags/6-javascript-dhtml-blog-entries.htm

Sorry, I wish it was better organized.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
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.