NgUpgrade: Unable to use templateUrl when upgrading Angular1 components

I found a quite cheap solution for the issue.

Just use template: require('./remote-url.component.html') instead of templateUrl: './remote-url.component.html' and it should work just fine!


After trying require with requireJS and the text plugin which did not work for me, I managed to make it work using 'ng-include' as follow:

angular.module('appName').component('nameComponent', {
template: `<ng-include src="'path_to_file/file-name.html'"></ng-include>`,

I hope this helps!


This is really frustating because the Angular upgrade documentation specifically says it's ok to use templateUrl. Never mentions this async issue. I've found a way around it by using the $templateCache. I didn't want to change my angular 1 directive because it is used my angular 1 apps and will also be used by angular 4 apps. So I had to find a way to modify it on the fly. I used $delegate, $provider, and $templateCache. My code is below. I also use this to remove the replace attribute since it is deprecated.

function upgradeDirective(moduleName, invokedName) {
    /** get the invoked directive */
    angular.module(moduleName).config(config);

    config.$inject = ['$provide'];
    decorator.$inject = ['$delegate', '$templateCache'];

    function config($provide) {
        $provide.decorator(invokedName + 'Directive', decorator);
    }

    function decorator($delegate, $templateCache) {
        /** get the directive reference */
        var directive = $delegate[0];

        /** remove deprecated attributes */
        if (directive.hasOwnProperty('replace')){
            delete directive.replace;
        }

        /** check for templateUrl and get template from cache */
        if (directive.hasOwnProperty('templateUrl')){
            /** get the template key */
            var key = directive.templateUrl.substring(directive.templateUrl.indexOf('app/'));

            /** remove templateUrl */
            delete directive.templateUrl;

            /** add template and get from cache */
            directive.template = $templateCache.get(key);
        }

        /** return the delegate */
        return $delegate;
    }
}

upgradeDirective('moduleName', 'moduleDirectiveName');

Most of the answers given here involve pre-loading the template in some way so as to make it available synchronously to the directive.

If you want to avoid doing this - e.g. if you have a large AngularJS application that contains many templates, and you don't want to download them all up front - you can simply wrap your directive in a synchronously loaded version instead.

E.g., if you have a directive called myDirective, which has an asynchronously loaded templateUrl which you don't want to download up front, you can do this instead:

angular
  .module('my-module')
  .directive('myDirectiveWrapper', function() {
    return {
      restrict: 'E',
      template: "<my-directive></my-directive>",
    }
  });

Then your Upgraded Angular directive just needs to supply 'myDirectiveWrapper' instead of 'myDirective' in it's super() call to the extended UpgradeComponent.