Loading relative templateUrl

Danny Nelson picture Danny Nelson · Apr 3, 2014 · Viewed 48k times · Source

I've been trying to find the best way to create a modular, scalable angular application. I really like the structure of projects like angular-boilerplate, angular-app, where all the related files are grouped together by feature for partials and directives.

project
|-- partial
|   |-- partial.js
|   |-- partial.html
|   |-- partial.css
|   |-- partial.spec.js

However, in all these examples, the template URL is loaded relative to the base url, not relative to the current file:

angular.module('account', [])
.config(function($stateProvider) {
  $stateProvider.state('account', {
    url: '/account',
    templateUrl: 'main/account/account.tpl.html', // this is not very modular
    controller: 'AccountCtrl',
  });
})

This is not very modular, and could become difficult to maintain in large projects. I would need to remember to change the templateUrl path every time I moved any of these modules. It would be nice if there was some way to load the template relative to the current file like:

templateUrl: './account.tpl.html'

Is there any way to do something like this in angular?

Answer

tannerlinsley picture tannerlinsley · Nov 12, 2014

The best way to do this now is using a module loader like browserify, webpack, or typescript. There are plenty of others as well. Since requires can be made from the relative location of the file, and the added bonus of being able to import templates via transforms or loaders like partialify, you don't even have to use template urls anymore. Just simply inline the Template via a require.

My old answered is still available below:

I wrote a post on exactly this subject and spoke on it at our local Angular Meetup. Most of us are now using it in production.

It is quite simple as long as your file structure is represented effectively in your modules. Here is a quick preview of the solution. Full article link follows.

var module = angular.module('myApp.things', []);

var all = angular.module('myApp.things.all', [
    'myApp.things',
    'things.someThing',
    'things.someOtherThing',
    'things.someOtherOtherThing',
]);

module.paths = {
    root: '/path/to/this/thing/',
    partials: '/path/to/this/thing/partials/',
    sub: '/path/to/this/thing/sub/',
};

module.constant('THINGS_ROOT', module.paths.root);
module.constant('THINGS_PARTIALS', module.paths.partials);
module.constant('THINGS_SUB', module.paths.sub);

module.config(function(stateHelperProvider, THINGS_PARTIALS) {

    stateHelperProvider.setNestedState({
        name: 'things',
        url: '/things',
        templateUrl: THINGS_PARTIALS + 'things.html',
    });
});

And then any sub modules or "relative" modules look like this:

var module = angular.module('things.someThing', ['myApp.things']);
var parent = angular.module('myApp.things');

module.paths = {
    root: parent.paths.sub + '/someThing/',
    sub: parent.paths.sub + '/someThing/sub/',
    partials: parent.paths.sub + '/someThing/module/partials/',
};

module.constant('SOMETHING_ROOT', module.paths.root);
module.constant('SOMETHING_PARTIALS', module.paths.partials);
module.constant('SOMETHING_SUB', module.paths.sub);

module.config(function(stateHelperProvider, SOMETHING_PARTIALS) {

    stateHelperProvider.setNestedState({
        name: 'things.someThing',
        url: "/someThing",
        templateUrl: SOMETHING_PARTIALS + 'someThing.html',
    });
});

Hope this helps!

Full Article: Relative AngularJS Modules

Cheers!