13

My intention is to load all the templates of my web app with one single call to an external JSON file containing a list of all the template names and values.

I am currently loading these templates on the run phase of my app:

app.run(function ($http, $templateCache) {
    $http.get('/templates/all.json').success(function (data) {
        var i;
        for (i = 0; i < data.length; i++) {
            $templateCache.put(data[i].name, data[i].template);
        }
    });
});

However, the Angular.js config phase executes before the run phase, so when I intend to load from the templateCache:

app.config(function($routeProvider, $locationProvider) {
    //App routing
    $routeProvider.
        //Homepage
        when('/', {templateUrl: 'home.html'}).

        //My schedule
        when('/my-schedule', {templateUrl: 'my-schedule.html'});
});

Angular tries to load home.html from the server, because the $templateCache hasn't been filled yet.

Suppose that all.json contains the templates for home.html and my-schedule.html for the prevous example.

Is it possible to fill $templateCache before configuring the app's $routeProvider?

pau.moreno
  • 4,407
  • 3
  • 35
  • 37
  • Look at this as it may help http://stackoverflow.com/questions/12346690/is-there-a-way-to-make-angularjs-load-partials-in-the-beginning-and-not-at-when/12346901#12346901 – Chandermani Mar 11 '13 at 12:30
  • @Chandermani, although I aleady based my idea on this answer, it doesn't solve what I'm asking, which is how to fill the `$templateCache` *before* configuring my `$routeProvider`. – pau.moreno Mar 11 '13 at 12:38
  • My bad i missed that part :( – Chandermani Mar 11 '13 at 14:15
  • did you try in `resolve` callback of `$routeProvider`? – charlietfl Mar 11 '13 at 15:39
  • @charlietfl Yes, I'm playing with `resolve`, but that won't let me rely on the `templateUrl` attribute in the `$routeProvider` config, will it? Instead, I guess I'll have to do the loading of templates manually. – pau.moreno Mar 11 '13 at 16:58
  • my thinking was you load the $templatecache in `resolve` , unless it already exists. What you are trying to do is difficult due to asynch. Not sure if config will look for `template` before `resolve` or not. No compiling can start though before `resolve` – charlietfl Mar 11 '13 at 17:02
  • look in source for angular-ui. they create modules for all the templates, then include those modules as dependencies for main module...might be able to do same – charlietfl Mar 11 '13 at 19:23
  • The templates are not loaded until a route becomes active, which can't happen during configuration. Preloading data into `$templateCache` should just work. Paths used won't be normalized, so if your route configuration has `templateUrl: "home.html"` then the key used to populate `$templateCache` should be `"home.html"` (not `"/home.html"`). – groner Mar 19 '13 at 18:34

3 Answers3

6

I had the same problem and after couple of hours spent on research I realized that I was asking myself the wrong question, since what I wanted to do wasn't necessarily loading templates using XHR but just being sure that they're cached and stored in one file.

I have grunt task compiling all my JADE templates to HTML and wrapping them in one big angular module which is loaded as a separate JS file called templates.js. All these things are done automatically in background, so after you've spent 10 minutes configuring it, you can actually forget the monkey work and focus on the code / markup.

(for the sake of brevity I'm going to skip the JADE part here)

  1. edit html file
  2. grunt-contrib-watch task:
    1. catches the change
    2. generates angular modules with $templateCache enabled
  3. my website is reloaded (using liveReload)

This is how I approached the problem using Grunt.js / JADE and html2js:

Head section of my index.jade file

  script(src='js/modernizr.js')
  script(src='js/vendor.js')
  script(src='js/templates.js')
  script(src='js/app.js')

Beginning of the main application module (using CoffeeScript here)

'use strict'
# Declare app level module which depends on filters, and services
App = angular.module('app', [ 
  'templates' // just include the module and forget it
  'foo'
  'bar']).config(...)

GruntFile.json (grunt.js config)

I needed to remove ca 80% of the code and left just tasks related to templates, consider it just a draft.

module.exports = (grunt)->
  imports = grunt.file.readJSON 'app/imports.json'
  grunt.initConfig
    pkg: grunt.file.readJSON 'package.json'



    watch:
      options:
        livereload: yes


      templates:
        files: 'app/**/*.jade'
        tasks: ['buildTemplates']

    jade:
      default:
        options:
          client: no
          wrap: no
          basePath: 'app/'
          pretty: yes
        files:
          'public/': ['app/**/*.jade']

    html2js:
      options:
        module: 'templates'
        base: 'public/'

      main:
        src: 'public/partials/**/*.html'
        dest: 'public/js/templates.js'


    connect:
      server:
        options:
          port: 8081
          base: 'public'
          keepalive: yes


      livereload:
        options:
          port: 8081
          base: 'public'
          # middleware: (connect, options)-> [lrSnippet, folderMount(connect, options.base)]

    copy:
      assets:
        files:[
          src:['**'], dest:'public/', cwd:'assets/', expand: yes
        ]



  grunt.loadNpmTasks 'grunt-contrib-concat'
  grunt.loadNpmTasks 'grunt-contrib-copy'
  grunt.loadNpmTasks 'grunt-contrib-coffee'
  grunt.loadNpmTasks 'grunt-contrib-clean'
  grunt.loadNpmTasks 'grunt-contrib-connect'
  grunt.loadNpmTasks 'grunt-contrib-compass'
  grunt.loadNpmTasks 'grunt-contrib-watch'
  grunt.loadNpmTasks 'grunt-contrib-livereload'
  grunt.loadNpmTasks 'grunt-jade'
  grunt.loadNpmTasks 'grunt-html2js'

  grunt.registerTask 'buildTemplates', ['clean:templates', 'copy:assets', 'jade', 'html2js:main', 'livereload']


  grunt.registerTask 'default', [ 'connect:livereload', 'watch']

Result

Single .js file containing list of all application templates wrapped in angular modules similar to this one:

angular.module("partials/directives/back-btn.html", []).run(["$templateCache", function($templateCache) {
  $templateCache.put("partials/directives/back-btn.html",
    "<a ng-href=\"{{href}}\" class=\"page-title-bar__back\"> <i class=\"icon-chevron-left\"> </i></a>");
}]);

Links

  1. grunt.js
  2. grunt html2js plugin
Rafal Pastuszak
  • 3,100
  • 2
  • 29
  • 31
2

if you use a HTTP interceptor, you can inject the $templateCache there:

    $provide.factory('myHttpInterceptor', ['$templateCache', function($templateCache) {
        return {
            request: function(config) {
                // do fancy things with $templateCache here
                return config;
            }
        };
    }]);
Joscha
  • 4,643
  • 1
  • 27
  • 34
2

This Fiddle is what you need.

Basically - you can just put the $templateCache key in the templateUrl: property value inside the $routeProvider configuration.

Rubinsh
  • 4,883
  • 10
  • 34
  • 41
  • Not really what he's looking for. He'd like to preload the templates before the route provider will use the templateUrl to load the template. I have the same problem, I have templates stored in CouchDB and unfortunately, AngularJS doesn't know how to convert JSON to html templates. – Loïc Faure-Lacroix Dec 13 '15 at 09:42