JakeHova
JakeHova

Reputation: 1375

Angular Template Cache with Service Worker Issue

I have a gulp setup that puts all my html in template cache for faster access in angular. I'm trying to add a service worker to my project, using sw-precache, so that it can be used offline. If I'm connected to the network, everything works fine. When I go offline, the requests for html resources (that are in the template cache) fail because it seems it is requesting the path from the network.

Is there something I need to add to my sw-precache config in order to have it defer to angular to handle retrieval of html files?

Upvotes: 0

Views: 885

Answers (2)

Paul Backhouse
Paul Backhouse

Reputation: 46

my original solution was not 100%

To solve this, use sw-precache and sw-toolbox

Using a gulp configuration you can setup sw-precache to cache you content and extend this with sw-toolbox to use cached responses based upon routing configuration

see: https://developers.google.com/web/ilt/pwa/using-sw-precache-and-sw-toolbox

Upvotes: 1

Paul Backhouse
Paul Backhouse

Reputation: 46

ok, so this is how I solved this. I am using Angular JS 1.6.4 with sw-precache.

I have CacheStorage via service workers, so using service workers I know I am expecting devices to support certain functionality, in my case we know our users will have Android Tablets with Chrome and support is valid.

I am developing a progressive web app with offline functionality.

So, the theory...I have directives which have templateUrls.

Using this post: https://thinkster.io/templatecache-tutorial

I basically have my directive code:

angular.module('app').directive('location',
['$timeout', 'notify.service', 'user.settings.service', 'log.service',
    function ($timeout, notify, userSettings, log) {
        return {
            restrict: 'EA',
            ... controller etc.., 
            templateUrl: '/App/core/directives/location.html'
        }
    }
]);

Now, when this app goes offline, the cached instances of the content was not kicking it - annoying.

So, after much procrastinating I got down and dirty.

My solutio is, keep the templateUrl as it is, but overwrite the content via the $templateCache service.

To do this, you append a RUN function with your directive (for clarity). We know the service worker cache representation of our Url files contains the common path, in my case: '/App/core/directives/location.html'.

So, using new technology in the browser, window.caches gives me access to the CacheStorage that the service workers uses, I can then use the API available: https://developer.mozilla.org/en-US/docs/Web/API/Cache

I can then use the match method to find the matching service worker cache content, read that stream of binary and convert to HTML and then tell $templateCache to replace it with the service worker cached value.

So, for completeness (and you can create a common service which replaces the cached values based on templateUrl - which I will be doing for each directive)

(function () {

    'use strict';

    var templateUrl = '/App/core/directives/location.html';

    // <location on-location='someFunc'></location>
    // provides a form/control to find a location either by GEO location or manual city search
    angular.module('app')
            .run(['$templateCache', function ($templateCache) {
                var cache = window.caches;

                cache.match(templateUrl, { ignoreSearch: true }).then(function (response) {

                    if (response) {
                        response.body.getReader().read().then(function (cachedResponse) {
                            // convert the Uint8Array value to HTML string
                            var content = new TextDecoder('utf-8').decode(cachedResponse.value);
                            $templateCache.put(templateUrl, content);
                            //console.log($templateCache.get(templateUrl)); // debug
                        });
                    }
                });


            }])
    .directive('location',
    ['$timeout', 'notify.service', 'user.settings.service', 'log.service',
        function ($timeout, notify, userSettings, log) {
            return {
                restrict: 'EA',
                ... controller, scope etc...
                templateUrl: templateUrl
            }
        }
    ]);  
})();

Draw backs...the RUN process is synchronous, so initially they have to hit the site online first...but thats how service worker needs to work anyway, so thats handled in training :)

I expect there to be a better option, but for the time being thats the solution I have, I will be creating a template service for replacing $templateCache values based on the var templateUrl each directive will have, so the code becomes cleaner in each directtive....i considered having a global arr of templates and files, but, just a bit obscure, think its cleaner for each directive

Upvotes: 2

Related Questions