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:
As you can see, this routing example makes use of three different templates:
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:
<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.
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") />
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 :)
Ah, good call. I can never remember which parts of the pathing is system-agnostic. I know you can do some things without problems.
Sorry, I wish it was better organized.