4

What's the simplest/modern way of caching partials in angularjs production?

Currently the code looks like:

$routeProvider.when('/error', {templateUrl: 'partials/error.html', controller: 'ErrorCtrl'});

Where the templateUrl is obviously an http path to a separate file. On mobile the loading time for that file is noticeable and I'd love to just cache everything.

MB.
  • 4,167
  • 8
  • 52
  • 79

1 Answers1

7

The main part of the answer is the $templateCache. An extract:

var myApp = angular.module('myApp', []);
myApp.run(function($templateCache) {
    $templateCache.put('templateId.html', 'This is the content of the template');
});

Any of the html templates, can be moved to the $templateCache, and the rest of our application will act as expected (no other changes required)

local-storage as a cache

In case, that we would like to keep the template on the client, we can use the local storage as well. This angular-local-storage extension would simplify lot of stuff.

So, let's adjust the run() to

  1. observe the local-storage, if we do not already have the template on the client
  2. issue the request to load the latest, if needed...
  3. put it into the caches (local-storage and $templateCache)

The adjusted code

.run([                  'localStorageService','$templateCache','$http',
    function myAppConfig(localStorageService , $templateCache , $http) {

    // The clearAll() should be called if we need clear the local storage
    // the best is by checking the previously stored value, e.g. version constant 
    // localStorageService.clearAll();

    var templateKey = "TheRealPathToTheTemplate.tpl.html";

    // is it already loaded?
    var template = localStorageService.get(templateKey);

    // load the template and cache it 
    if (!template) {
        $http.get(templateKey)
            .then(function(response) {

                // template loaded from the server
                template = response.data;

                localStorageService.add(templateKey, template);
                $templateCache.put(templateKey, template);
            });
    } else {

        // inject the template
        $templateCache.put(templateKey, template);
    }

    }])

So, this way, we do profit from the local-storage. It is filled with the "template" from the server, kept there... and therefore not loaded next time.

NOTE: Very important is also to inject some version key/value and check it. If the Local storage is out-dated... all templates must be reloaded.

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • The partials I have are pretty big and I'd rather they not be in one big file. Can I load the partials in $templateCache from static files? – MB. Jan 20 '14 at 08:48
  • I've updated the answer. If I do understand your issue correctly, what we can do, is to use the **local storage**. This will (cooperating with the $templateCache) do the job... load stuff once. – Radim Köhler Jan 20 '14 at 09:25
  • Related to this, a situation I have just run into, if you use `$http.get()` to load in the templates to `$templateCache` similar to the above it is possible that the template is not loaded before the route requires the template and as such is not loaded correctly, is there a way it can be attached to the resolve object or something similar? – adamK Jan 20 '14 at 11:04
  • That's why we should use the `.run()` http://docs.angularjs.org/api/angular.Module: *Use this method to register work which should be performed when the injector is done loading all modules* – Radim Köhler Jan 20 '14 at 11:07
  • Understood and agree, but I still encounter the above issue. If the templateUrl's require a GET from the server, are hard coded into a script tag or explicitly defined in the `$templateCache.put()` method everything works as expected but if I attempt to load into the template cache via $http in the run phase they are not loaded in time and no template is displayed. I can ask a new question if it would be more appropriate. – adamK Jan 20 '14 at 11:17
  • 1
    @NinjaPants I understand, that even if called in the run, the promise could be resolved later. But in that case, the $templateCache should be not filled, and the template will be loaded directly. Meanwhile the get will finish, and for next time, the localstorage is populated. It is working for me. But, if you'll ask new question, you can pass more details (your code) and someone can quickly find out.. because, the above approach in my answer - is working for me. at least for me ;) – Radim Köhler Jan 20 '14 at 11:31
  • I'll keep working on it and if not i'll post a new question, nice answer though thank you. – adamK Jan 20 '14 at 11:39
  • One more question: can this be made to run when the user gets to the page, or maybe a short while after, and *not* on demand? My issue is that a user presses smth, and on mobile it takes a while for the partial to get for some reason. – MB. Jan 29 '14 at 21:11
  • 1
    The answer here is: if we do not **preload** that as soon as possible - then this will happen: Angular is asking `$templateCache` at the moment it needs the template. All the templates already processed *(cached)* will be available. Any missing, will immediately force the call to the server to get that template. So what we are trying to achieve, is to find the best place, where to pre-load all the "heavy" templates, **before user** will touch them. To put them into `$templateCache` (and local storage) before these are required. Only in this case we will go for them only once. Is it answer? – Radim Köhler Jan 30 '14 at 03:48