Skip to main content
Ben Nadel at RIA Unleashed (Nov. 2009) with: Ed Sullivan
Ben Nadel at RIA Unleashed (Nov. 2009) with: Ed Sullivan

Inlining AngularJS Templates Using ColdFusion

By
Published in , Comments (3)

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.

Want to use code from this post? Check out the license.

Reader Comments

1 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") />
1 Comments

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 :)

15,848 Comments

@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:

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

Sorry, I wish it was better organized.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel