How to Include View/Partial Specific Styling in Angularjs

How to include view/partial specific styling in AngularJS

I know this question is old now, but after doing a ton of research on various solutions to this problem, I think I may have come up with a better solution.

UPDATE 1: Since posting this answer, I have added all of this code to a simple service that I have posted to GitHub. The repo is located here. Feel free to check it out for more info.

UPDATE 2: This answer is great if all you need is a lightweight solution for pulling in stylesheets for your routes. If you want a more complete solution for managing on-demand stylesheets throughout your application, you may want to checkout Door3's AngularCSS project. It provides much more fine-grained functionality.

In case anyone in the future is interested, here's what I came up with:

1. Create a custom directive for the <head> element:

app.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, current) {
if(current && current.$$route && current.$$route.css){
if(!angular.isArray(current.$$route.css)){
current.$$route.css = [current.$$route.css];
}
angular.forEach(current.$$route.css, function(sheet){
delete scope.routeStyles[sheet];
});
}
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;
});
}
});
}
};
}
]);

This directive does the following things:

  1. It compiles (using $compile) an html string that creates a set of <link /> tags for every item in the scope.routeStyles object using ng-repeat and ng-href.
  2. It appends that compiled set of <link /> elements to the <head> tag.
  3. It then uses the $rootScope to listen for '$routeChangeStart' events. For every '$routeChangeStart' event, it grabs the "current" $$route object (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" $$route object (the route that the user is about to go to) and adds any of its partial-specific css file(s) to the <head> tag.
  4. And the ng-repeat part 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 the scope.routeStyles object.

Note: this requires that your ng-app attribute is on the <html> element, not on <body> or anything inside of <html>.

2. Specify which stylesheets belong to which routes using the $routeProvider:

app.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']
})
}]);

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. Note that 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 <head> directive will simply do nothing for that route. Note also that 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.

3. You're done
Those two things setup everything that was needed and it does it, in my opinion, with the cleanest code possible.

Hope that helps someone else who might be struggling with this issue as much as I was.

ng-include not loading partial view

My file is in the folder which is on the same level that pagination folder.

You're propably passing a wrong path for the html template.

You have to refer to your template directory as if you're writing in your index.html file. So no matter which html template the ng-include directive exists you have to give it the path as if your root is the place where index.html exists.

Also try to avoid using '/' before the path.

e.g.

Suppose you're having the following folder tree:

---index.html

---/templates/app.html

---/tempates/pagination/view.html

In case you're trying to include the view.html in your app.html then you would do it like this:

<ng-include src="'templates/pagination/view.html'"></ng-include>

I hope it helps.

How to require CSS into AngularJS templates with webpack?

To apply css to only one component you have to use shadow dom, however angularjs 1.5.x does not use shadow dom. But from your specification you have 2 options:

1. Load css file in router or via custom directive.

As suggested how-to-include-view-partial-specific-styling-in-angularjs you caninclude your custom css files using either custom directive or by using angular-css module (mode info about this module). I'd suggest to use the second option (angular-css module). Another example how to use angular-css module. However you will have to use specific styles to apply only to /static/templates/authentication/login.html file.

2. Load css files using module local scope.

Another way is to break you application to specific ES6 modules (don't get this mixed up with angular's modules) and include them in main ES6 module. To understand ES6 modules follow this link. And then you can use local scope with css-loader css-loader#local-scope. This option might be harder to make it work, because you will have to change your build process and split application to seperate modules, but you will get option to apply stylesheets to only one module.


To be clear the best sollution might be the first one, no need to change your build process and you can just add one NG module and you are good to go. No need to talk about that you can then load CSS files to your directives or components. But as you stated you need to apply your changes only to one particular .html file, so going for second option might more suit your needs.



Related Topics



Leave a reply



Submit