Search code examples
angularjsgruntjsrequirejsgrunt-contrib-requirejsangular-templatecache

How to load $templateCache before routes are created in app.config?


In my AngularJS app, I am trying to create a build using grunt and following plug-ins.

  • grunt-contrib-clean
  • grunt-contrib-requirejs
  • grunt-angular-templates
  • grunt-angular-copy

I am able to successfully create the main.js file with all the Javascript code (controllers etc) and also able to append the partials using ngtemplates to main.js.

GruntFile.js

ngtemplates:{
      options: {
       append: true, 
       bootstrap:  function(module, script) {
            return 'require([\'angular\', \'app\'], function(angular, app) { app.run([\'$templateCache\', function($templateCache) {' + script + '}]); });';
        }
      },
      app:{
        cwd:      'app',
        src:      '*/partials/*.html',
        dest:     'build/main.js'
      }
    },

requirejs: {
  compile: {
    options: {
      baseUrl: './app',
      mainConfigFile: "./app/main.js",
      optimize: 'none',
      name: 'main',
      out: "./build/<%= pkg.name %>.js",
      preserveLicenseComments: false,
          paths: {
          'domReady': 'empty:',
          'angular': 'empty:',
          "uiRouter": 'empty:',
          "ui-grid": 'empty:',
          "ng-dialog": 'empty:',
          "jquery": 'empty:',
          "ui-bootstrap": 'empty:',
          "d3js": 'empty:',
          "nvd3": 'empty:',
          'angular-nvd3': 'empty:',
          'angucomplete-alt': 'empty:',
          'spin': 'empty:',
          'angular-spinner': 'empty:',
          'moment': 'empty:',
          'angular-moment': 'empty:',
          'angular-sanitize': 'empty:',
          'ng-csv': 'empty:',
          'ng-cookies': 'empty:'
      }
    }
  }
}

In routes.js I have

define(['app'], function(app) {
    'use strict';
    return app.config(function($stateProvider) {
        var routes = [
        {
            state: 'home',
            url: '/home',
            templateUrl: 'app/home/partials/home.html',
            controller:'homeController'
        } 
];

        $stateProvider.state(route.state,
            {
                url: route.url,
                // templateUrl: route.templateUrl,
                templateProvider: function($templateCache) {
                    return $templateCache.get(route.templateUrl);
                },
                controller:route.controller,
                params:route.params
            }
        );

the bootstrap code which was injected by grunt-contrib-requirejs at the end of the build/main.js file.

require(['angular', 'app'], function(angular, app) { app.run(['$templateCache', function($templateCache) {  
  'use strict';

  $templateCache.put('home/partials/home.html',
    "<div class=\"jumbotron text-center\">\r" +
    "\n" +
    "\t<p>{{message}}</p>\r" +
    "\n" +
    "</div>"
  );
  );
}]); });

Now the problem is, the main.js has the bootstrap code at the bottom appended to it. Which puts the templates into $templateCache. But when the application loads, it runs the config code first and then the app.run() is called. Which is obvious. Hence, the $templateCache.get() gets undefined values in routes.js.

How can I tackle this problem?


Solution

  • Thanks for your answers guys. But I found my mistakes. I made a few changes in current implementation and it started working. I am putting it here so it could be helpful to someone like me in future.

    1. I changed my Gruntfile.js and updated the ngtemplates task to create a stand alone templates.js file instead of appending it into existing main.js. I don't even need the append: false option but keeping it just for sake of it. Also changed the bootstrap: option to use define instead of require

      ngtemplates: {
      options: {
      append: false,
      bootstrap: function(module, script) {
        return 'define([\'angular\', \'app\'], function(angular, app) { app.run([\'$templateCache\', function($templateCache) {' + script + '}]); });';
       }
      },
       app: {
       cwd: 'app',
       src: '*/partials/*.html',
       dest: 'app/templates.js'
       }
      },
      
    2. I changed my routes.js (inserted below). Added the 'templates' module depenncy so that requirejs would load the templates.js and run it, which will execute the $templateCache.put() code before it comes to return $templateCache.get() line. And by that time the templcateCache will be ready. I also was doing a silly mistake by not using the same KEY to get the template which I was using to putting it in the templateCache. I had an extra app/ in front of the key while trying to pull it back from the templateCache.

      define(['app', 'templates'], function(app) {
        'use strict';
        return app.config(function($stateProvider) {
              var routes = [{
                state: 'home',
                url: '/home',
                templateUrl: 'home/partials/home.html',
                controller: 'homeController'
              }];
      
      
      
              $stateProvider.state(route.state, {
                url: route.url,
                // templateUrl: route.templateUrl,
                templateProvider: function($templateCache) {
                  return $templateCache.get(route.templateUrl);
                },
                controller: route.controller,
                params: route.params
              });
      

    after these changes, my build folder was ready to be used as expected.