46

After the Angular app is loaded I need some of the templates to be available offline.

Something like this would be ideal:

$routeProvider
  .when('/p1', {
    controller: controller1,
    templateUrl: 'Template1.html',
    preload: true
  })
andersh
  • 8,105
  • 6
  • 39
  • 30
  • 3
    Sobieck00 gives the best answer on here which matches the original question http://stackoverflow.com/a/23522925/956658 – Dreamwalker Jun 20 '14 at 13:13

5 Answers5

57

This is an addition to the answer by @gargc.

If you don't want to use the script tag to specify your template, and want to load templates from files, you can do something like this:

    myApp.run(function ($templateCache, $http) {
        $http.get('Template1.html', { cache: $templateCache });
    });

    myApp.config(function ($locationProvider, $routeProvider) {
        $routeProvider.when('/p1', { templateUrl: 'Template1.html' })
    });
andersh
  • 8,105
  • 6
  • 39
  • 30
  • 8
    by the way, `$http.get('Template1.html', {cache: $templateCache});` should have the same effect. Although, it does not really make much of a difference :) – garst Sep 10 '13 at 15:53
  • 1
    This is definitely a simpler alternative than what I suggested. Thanks again :) – andersh Sep 11 '13 at 07:11
  • 2
    I prefer this solution as it doesn't require building a JavaScript file from HTML templates. – Daniel Buckmaster Dec 17 '13 at 04:30
  • this line " $http.get('Template1.html', { cache: $templateCache });" also means that you add it to angular cache? – GomuGomuNoRocket Dec 19 '16 at 10:03
  • I've tried this out, but since the http.get is asynchronous my template hasn't been loaded yet on the point where I acutally need it. Anyone know how to work around that? – Stif Jan 11 '17 at 13:03
  • doesn't work for me. I even ran it in console, and nothing happened. – Saeed Neamati Jan 27 '17 at 06:21
45

There is a template cache service: $templateCache which can be used to preload templates in a javascript module.

For example, taken from the docs:

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

There is even a grunt task to pre-generate a javascript module from html files: grunt-angular-templates

Another way, perhaps less flexible, is using inline templates, for example, having a script tag like this in your index.html:

<script type="text/ng-template" id="templates/Template1.html">template content</script>

means that the template can be addressed later in the same way as a real url in your route configuration (templateUrl: 'templates/Template1.html')

garst
  • 6,042
  • 1
  • 29
  • 24
  • 1
    Thanks, just what I was looking for! I would really like being able to specify the template file in $templateCache.put(), the script tag alternative messes up my IDE, and I'm not using grunt. I ended up using $http. See my own answer for details. – andersh Sep 10 '13 at 13:26
  • I haven't tested that Grunt plugin yet but ... does it include controllers as well? Or just the templates? Might be nice to preload everything possible, for loading views quickly. Thanks! – derrylwc May 07 '14 at 01:33
  • +1 for the Inline templates. The inline templates allow for faster initial load, but with the flexibility of replacing the content later. – elkelk Aug 07 '14 at 13:07
  • @derrylwc: I am struggling with the opposite problem in the moment. I have an project, created with a grunt generator (grunt-angular-fullstack), which automatically includes and configures a lot of grunt tasks. One of them is grunt-angular-templates. As I want to intercept the loading from the server with my authentication framwork, I need the request to the server, but I do not get them. So yes, it also prloads the controller.js files. – andreas Sep 05 '14 at 07:25
  • 13
    In case your template needs to be fetched from a URL: `myApp.run(function($templateRequest) { $templateRequest('/url/to/template.html', true); });` – Blaise Mar 17 '15 at 09:37
28

I think I have a slightly improved solution to this problem based on Raman Savitski's approach, but it loads the templates selectively. It actually allows for the original syntax that was asked for like this:

$routeProvider.when('/p1', { controller: controller1, templateUrl: 'Template1.html', preload: true })

This allows you to just decorate your route and not have to worry about updating another preloading configuration somewhere else.

Here is the code that runs on start:

angular.module('MyApp', []).run([
    '$route', '$templateCache', '$http', (function ($route, $templateCache, $http) {
        var url;
        for (var i in $route.routes) {
            if ($route.routes[i].preload) {
                if (url = $route.routes[i].templateUrl) {
                    $http.get(url, { cache: $templateCache });
                }
            }
        }
    })
]);
Thomas Sobieck
  • 1,416
  • 1
  • 20
  • 27
  • 4
    I would change it slightly to only not preload, if there's an explicit `preload: false` so the preloading is enabled for a route by default. But I think that descision is personal taste and depends on what you want to do. Besides that great snippet! +1 – Anticom Jul 01 '14 at 07:55
  • When I wrote that I was just wanting to load two routes out of about 20 or so. So, the explicit `preload: true` worked a little better for me. – Thomas Sobieck Jul 01 '14 at 11:26
  • 1
    This is by far the best answer. – Fernando Silveira Mar 04 '15 at 15:24
  • 1
    I am very glad to find your response here..I been strugling to find a way to cache my templates..thanks – user1455719 Jun 14 '15 at 04:39
  • Could some one please explain the "if (url = $route.routes[i].templateUrl)", this is an assignment - when would this return false? – CountZero Jan 03 '16 at 17:46
  • @CountZero JavaScript will equal an empty String to false. If any String is set at all, no matter what value it has (it might even be "0" or "false"), it will equal to true – Ahatius Mar 18 '16 at 09:18
  • 1
    If, like me, you got here looking for a solution using uiRouter and like this idea: [try this](http://stackoverflow.com/a/43785618/631295). It will load the template for the state and any views it has defined. – Knyri May 04 '17 at 14:33
  • how can one preload templates defined in component and not in router state? – indusBull Oct 27 '17 at 17:10
18

Preloads all templates defined in module routes.

angular.module('MyApp', [])
.run(function ($templateCache, $route, $http) {
    var url;
    for(var i in $route.routes)
    {
      if (url = $route.routes[i].templateUrl)
      {
        $http.get(url, {cache: $templateCache});
      }
    }
})
Raman Savitski
  • 178
  • 1
  • 5
  • What happen if the content of the template changes dynamically? Is this showed properly or will show the same content as it comes from the cache? – Mr. DMX Oct 25 '16 at 13:58
  • 1
    If content is dynamic - there is no sense to "preload" it. Or I don't understand your case. – Raman Savitski Mar 24 '17 at 13:16
0

if you wrap each template in a script tag, eg:

<script id="about.html" type="text/ng-template">
<div>
    <h3>About</h3>
    This is the About page
    Its cool!
</div>
</script>

Concatenate all templates into 1 big file. If using Visual Studio 2013,Download Web essentials - it adds a right click menu to create an HTML Bundle

Add the code that this guy wrote to change the angular $templatecache service - its only a small piece of code and it works :-)

https://gist.github.com/vojtajina/3354046

Your routes templateUrl should look like this:

        $routeProvider.when(
            "/about", {
                controller: "",
                templateUrl: "about.html"
            }
        );
Spudley
  • 166,037
  • 39
  • 233
  • 307
Simon Dowdeswell
  • 1,001
  • 11
  • 19