Update: another good solution for this topic is to use the external template engine found here.
A question recently came up on the Knockout forums about how to get better design time support in Visual Studio when working with jQuery templates and how to incorporate external template files into Knockout projects. Here are three different takes on solving both of these problems that each build on the previous idea.
Level One – Load individual template files
- Store each template in a
.htmlfile without the
scripttags. You could use a different extension, but using
.htmwill ensure that both the IDE will treat it properly and that the web server will serve it up without further configuration.
- Make an AJAX request for each template file that you need and inject it into the document inside of a
- Use a convention that the filename without the extension is the ID of the template (
idattribute of the
- Make sure that all of the template files have been loaded prior to calling
First we store our templates in individual
.html files. For example, suppose I have templates for a read-only view and for an editable view of an item. My read-only template might be stored in a file called
Templates/itemTmpl.html and look like:
1 2 3 4 5 6 7
On my page load, I would load my templates using something like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
ensureTemplates function will load each template that is required using our convention that the name of the file matches the
id of the script. We inject the
script tag into the document, as if it had been there the whole time. We keep track of how many have been loaded and in the
success callback of the last one to load we call
Note: We probably should consider some additional error handling here to make sure that we either retry loading any templates that fail or at least present the user with an error message if all of the templates fail to load.
- Gives each page the flexibility to load only the templates that it needs
- Gives good Intellisense and syntax highlighting in Visual Studio
- No further configuration necessary
- The requests are a bit chatty, as it makes individual requests for each file.
- Have to coordinate waiting for all files to load.
Level Two – Load a single file generated at build time
- As in Level One, store each template in a
- At build time, generate a single html file that includes all of your template files and wraps them in their
scripttags. Without being wrapped in their
scripttags or at least some identifiable container, we would not be able to easily understand where the templates start and end.
- Make an AJAX request for the single
.htmlfile and call
ko.applyBindingsin the success callback of that request.
We would store our templates in the same manner, but then during our build we would produce a single file that contains all of our templates. Here is one way to produce such a file using MSBUILD for a .NET Web Application project.
Open your Web Application’s
.csproj file. At the end of the file uncomment the
AfterBuild task and make it look something like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
On each build, we first delete our composite file that I named
all.html. Then, we call a target named
PrepareOneTemplate for each of our template files. The
PrepareOneTemplate target simply builds a string that wraps the template file contents in an appropriate script tag and writes it to the composite file. The end result is a single file that contains all of the script tags for our templates.
There certainly are many ways that this file could be generated. I’m sure that most people could find a way to generate it as part of their build process, even by just calling some shell commands.
- A single AJAX request is made for the templates.
- Gives good Intellisense and syntax highlighting in Visual Studio, as you would still be always editing the individual
- Final project does not even need to include the individual .html files. If someone accidentally browsed to the composite
.htmlfile they would not see anything visible.
- If we need to load different subsets of templates on each page, then we might have to do some work in the build to properly generate a variety of composite files.
Level Three – Reference a script generated at build time
- As in Level One, store each template in a
- At build time, generate a single
- Reference the script on your page prior to your code that calls
This time, we can use the same technique as Level Two in MSBUILD, we just need to generate lines that look like:
This could even just do a
document.write with the script tag and it would work or append it without the jQuery. I just like appending it to the body, as if it had been there all along.
The MSBUILD task would look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
We again wrap the template file contents in a
script tag. Then we replace all quotes with
Again, I am sure that there are many ways that this file could be generated as well, possibly by processing the files with regular expressions.
- No need to add code for making an AJAX request, as the script tag would handle it naturally.
- Gives good Intellisense and syntax highlighting in Visual Studio, as you would still be always editing the individual .html template files.
- Could pull templates cross-domain, although doubtful that it would be a normal scenario.
- Final project does not even need to include the individual
- If we need to load different subsets of templates on each page, then we might have to do some work in the build to properly generate several scripts.
So far, I am happiest with the Level Three method. All three methods give you a decent experience in the IDE, but the last one is easy to use on a page and the build process takes care of the work. Any other ideas/thoughts/methods for including external templates while getting a good design-time experience?