This is a simple module for AngularJS that provides the ability to have route-specific CSS stylesheets, by integrating with Angular's built-in $routeProvider service.
It allows you to declare partial-specific or route-specific styles for your app using
Angular's built-in $routeProvider service. For example, if you are already using
$routeProvider, you know that it allows you to easily setup your SPA routes by declaring
a .when() block and telling Angular what template (or templateUrl) to use for each
route, and also which controller to associate with that route. Well, up until now, Angular
did not provide a way to add specific CSS stylesheets that should be dynamically loaded
when the given route is hit. This solves that problem by allowing you to do something like this:
angular.module('myApp', ['ngRoute','routeStyles'])
.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/some/route/1', {
templateUrl: 'partials/partial1.html',
controller: 'Partial1Ctrl',
// css files can be declared for each route
css: 'css/partial1.css'
})
.when('/some/route/2', {
// css files can also be omitted completely (if a route does not need them)
templateUrl: 'partials/partial2.html',
controller: 'Partial2Ctrl'
})
.when('/some/route/3', {
templateUrl: 'partials/partial3.html',
controller: 'Partial3Ctrl',
// css files can optionally be declared as an array
css: ['css/partial3_1.css','css/partial3_2.css']
});
// more routes can be declared here
}]);Using bower:
bower install angular-route-styles
OR
Using GitHub:
git clone https://github.com/tennisgent/angular-route-styles
1) Include the route-styles.js file to your index.html file
<!-- should be added at the end of your body tag -->
<body>
...
<script scr="path/to/route-styles.js"></script>
</body>2) Declare the 'routeStyles' module as a dependency in your main app
angular.module('myApp', ['ngRoute','routeStyles' /* other dependencies here */]);NOTE: you must also include the ngRoute service module from angular, or at least make the
module available by adding the angular-route.js (or angular-route.min.js) script
to your html page.
NOTE: this code also requires that your Angular app has access to the <head> element. Typically this
requires that your ng-app directive is on the <html> element. For example: <html ng-app="myApp">.
3) Add your route-specific styles to the $routeProvider in your app's config
angular.module('myApp', ['ngRoute','routeStyles'])
.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/some/route/1', {
templateUrl: 'partials/partial1.html',
controller: 'Partial1Ctrl',
css: 'css/partial1.css'
})
.when('/some/route/2', {
templateUrl: 'partials/partial2.html',
controller: 'Partial2Ctrl'
})
.when('/some/route/3', {
templateUrl: 'partials/partial3.html',
controller: 'Partial3Ctrl',
css: ['css/partial3_1.css','css/partial3_2.css']
});
// more routes can be declared here
}]);Things to notice:
- Specifying a css property on the route is completely optional, as it was omitted from the
'/some/route/2'example. If the route doesn't have a css property, the service will simply do nothing for that route. - You can even have multiple page-specific stylesheets per route, as in the
'/some/route/3'example above, where the css property is an array of relative paths to the stylesheets needed for that route.
This config adds a custom css property to the object that is used to setup each page's route. That object gets passed to each '$routeChangeStart' event as .$$route. So when listening to the '$routeChangeStart' event, we can grab the css property that we specified and append/remove those <link /> tags as needed.
.directive('head', ['$rootScope','$compile',
function($rootScope, $compile){
return {
restrict: 'E',
link: function(scope, elem){
var html = '<link rel="stylesheet" ng-repeat="(routeCtrl, cssUrl) in routeStyles" ng-href="{{cssUrl}}" >';
elem.append($compile(html)(scope));
scope.routeStyles = {};
$rootScope.$on('$routeChangeStart', function (e, next) {
if(next && next.$$route && next.$$route.css){
if(!angular.isArray(next.$$route.css)){
next.$$route.css = [next.$$route.css];
}
angular.forEach(next.$$route.css, function(sheet){
scope.routeStyles[sheet] = sheet;
});
}
});
$rootScope.$on('$routeChangeSuccess', function(e, current, previous) {
if (previous && previous.$$route && previous.$$route.css) {
if (!angular.isArray(previous.$$route.css)) {
previous.$$route.css = [previous.$$route.css];
}
angular.forEach(previous.$$route.css, function (sheet) {
scope.routeStyles[sheet] = undefined;
});
}
});
}
};
}
]);This directive does the following things:
- It compiles (using
$compile) an html string that creates a set of tags for every item in thescope.routeStylesobject usingng-repeatandng-href. - It appends that compiled set of
<link />elements to the<head>tag. - It then uses the
$rootScopeto listen for'$routeChangeStart'events. For every'$routeChangeStart'and$routeChangeSuccessevent, it grabs the "current"$$routeobject (the route that the user is about to leave) and removes its partial-specific css file(s) from the<head>tag. It also grabs the "next"$$routeobject (the route that the user is about to go to) and adds any of its partial-specific css file(s) to the<head>tag. - And the
ng-repeatpart of the compiled<link />tag handles all of the adding and removing of the page-specific stylesheets based on what gets added to or removed from thescope.routeStylesobject.