FED-icons-01 FED-icons-02 FED-icons-03 FED-icons-04 FED-icons-05 FED-icons-06 FED-icons-07 FED-icons-08 FED-icons-09 FED-icons-10 FED-icons-11

Reusability

Recently, I was building a new feature for a large Angular application. This application is extremely modular and each feature was designed for reuse. This being the case, when a new feature is built, it is important to be diligent about utilizing existing code

I mention the above to help explain the challenge. The application contains a directive for a slide-out panel. The slide-out panel is reused throughout the application and its content relates to whichever state / view / configuration the user is on. This is possible because the directive accepts a templateUrl in order to specify the desired view.

New Feature

The project required the ability to edit user settings along with potentially any number of other configurations. The available functionality would be passed to the front-end via a service and each functional item would be displayed as a link or button in the UI.

app.factory('linksFactory', function($http){
    _getLinks: function(url){
        return $http.get(url);
    }
    return {
        getLinks: _getLinks
    }
});
controller: function($scope){
    linksFactory.getLinks('/path_to_service')
        .success(function(data){
            $scope.links = data.links;
        })
        ...
<li ng-repeat="link in links">
    <a ng-click="getContent(link.id)">link.title</a>
</li>

When interacted with, each link would pass an id to a function which in-turn would make a service call for data. The data would then be passed to the slide-panel via a template. This template would be based off the 'dataType' returned.

{
    id: '12345',
    title: 'Content A',
    dataType: 'iframe',
    value: '/path_to_url'
}

Initial Thought

The simplest and most obvious approach would be to create template files for the various data types returned, whether it form inputs, plain text, iframe or some other media type. Based on the data type returned from the server, we would compile the relevant template with any dynamic data and pass this template url to the slide-panel directive.

Although this would achieve the desired result, I stopped to think whether server interaction for additional template files was necessary especially when some of these files may only have a single line of code.

In Comes $templateCache

"The first time a template is used, it is loaded in the template cache for quick retrieval. You can load templates directly into the cache in a script tag, or by consuming the $templateCache service directly." - Angular docs

$templateCache accepts a path to a template and some data. This data can be html.

$templateCache.put('path_to_file.html', someHTML);

I generally don't like having Markup in my JavaScript but I decided to ignore my own advice and create a service to return HTML snippets due to the length of the HTML being used and also to illustrate this approach.

app.factory('templateFactory', function(){
    _getHTML: {
        textInput: '<input type="text" ng-model="data.value" />',
        paragraph: '<p>{{data.value}}</p>',
        iframe: '<iframe src="{{data.value}}" />',
        image: '<img src="{{data.value}}" />'
        ...
    }
    return {
        getHTML: _getHTML
    }
});

$templateCache allows me to fake the existence of actual files.

var html = $compile(templateFactory.getHTML[data.dataType])($scope);
$templateCache.put('/fakeTemplate.html', html);

Here I put a template in $templateCache using a path to a file that doesn't actually exist. I also pass in the relevant compiled HTML. Now, I initialize the slide-panel directive passing through the same path as cached.

<slide-panel-directive templateUrl="/fakeTemplate.html"></slide-panel-directive>

Angular will retrieve the cached file when the slide-panel compiles its content.

The main 'gotcha' with this approach is that the path needs to match exactly for Angular to retrieve the cached file. If you are massaging path names etc. be sure to check that the path you are dumping into cache is the same path that is being used for retrieval.

This approach may not suit many real world situations, but I wanted to explore $templateCache in more detail and perhaps this could reduce processing time in one of your applications in the future.


Peter Unsworth

Founder / Application Architect