Lazy template loading with knockoutjs
« Monday, June 03, 2013 »

knockoutjs

Knockoutjs templating is one nice way to work because it's not creating any dependency to your project. The data-bind attribute might not be as sexy as the handlebars style templating, but it does the job.

In the tutorials located on the site, we can see everywhere that using named templates can be achieved like that:

1
2
3
<script type="text/html" id="mytemplate">
...some html...
</script>

And then, somwhere in a the html, you can call this template by using its id. This will work very well but something like that will not.

1
<script type="text/html" id="mytemplate" src="mytemplate.html"></script>

I can't say for sure but to me, it is a bug and it should naturally work. As I understand, it might not be possible for knockout to read the scripts of scripts that are loaded with src. The first version is actualling creating an Element with a vissible innerHTML content. The script tag will appear as an empty element. Knockoutjs doesn't like undefined values.

After thinking about it, I some time ago came up with a solution. The idea was to use an observable to get the template data. If the template wasn't yet loaded, it would yield a default template. If the template was already loaded, then it would send the actual name.

As far as I can remember, it worked nicely. I never published it and I probably won't. It was checking for the type of the modelview and returning the right template for the modelview and at the same time, it would lazy load the modelview.

Today, I came accros a question over stackoverflow. Someone was asking how to lazy load templates and I often encounter people falling back to external templating engine such as jQuery or underscore or whatever… But why use a different templating engine when the knockout one is working.

It might be even faster than external templates engines because knockout isn't parsing text but simply copying a DOM tree which should be easier to do than parsing back and forth strings to generate new DOM elements.

For that reason, I decied to publish a plugin that I called knockout-lazy-template. What it does is simple. It lazy load templates whenever they are needed. Nothing fancy over here.

It has only one function and one binding for the moment.

  • ko.lazyTemplate.init
  • binding handler: lazy-template

The init function takes one parameter with options. Currently it only has one option but I know some options that could be useful in the future.

Lets check an example:

1
2
3
4
5
ko.lazyTemplate.init({
    loader: function (name, callback){
        jQuery.get('/templates/' + name + '.html', callback);
    }
});

It's quite simple really. The loader option is the only possible option for now. It is a function that takes a name and a callback as argument. The name is the template name to be loaded and the callback is a callback with the content you want to load. In my example, I'm querying a file that could be called reports and located at /templates/reports.html.

What happen is that if the template for that name is already loaded, the loader will never be called. If the template is not loaded, it will be called. The jquery call will send back the content back to the callback that will trigger knockoutjs that the template is now available.

Behind the scene, it really feels like a hack. I send a computed value to the template binding. The template receives an empty template unless the template is loaded. When the template is loaded, the callback updates and observable that will trigger the computed value and voila! The template is updated as you expected.

The also less funny thing is that even if I load dynamically a template and the template is an empty string. Knockoutjs will fail so I had to literally prepend something to the received content to make sure it's not generating an empty element. And then knockoutjs is all happy rendering some whitespace while the templates is getting loaded.

Here's the small hack: https://github.com/llacroix/knockout-lazy-template/blob/master/src/knockout.lazy-template.js#L84

The project is located here: https://github.com/llacroix/knockout-lazy-template

I'm pretty sure that there are issues, I took some part of the code from my old code. For that reason, I don't have a real copy of the template binding with lazy loading. This is just a question of sending the right parameters to the template binding.

comments powered by Disqus

Copyright © 2015 Loïc Faure-Lacroix