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:
- It compiles (using
$compile
) an html string that creates a set of<link />
tags for every item in thescope.routeStyles
object usingng-repeat
andng-href
. - It appends that compiled set of
<link />
elements to the<head>
tag. - 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. - 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 thescope.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
Why Is @Font-Face Throwing a 404 Error on Woff Files
Get Two Columns With Different Background Colours That Extend to Screen Edge
How to Calculate the Viewport Width (Vw) Without Scrollbar
100Vw Causing Horizontal Overflow, But Only If More Than One
Should I Use 'Border: None' or 'Border: 0'
Offsetting Columns Is Not Working (Bootstrap V4.0.0-Beta)
How to Use a Unitless CSS Variables and Later Add the Needed Unit
Complete Styles for Cross Browser CSS Zoom
Filter: Blur(1Px); Doesn't Work in Firefox, Internet Explorer, and Opera
CSS Transition Auto Height Not Working
Safari/Chrome (Webkit) - Cannot Hide Iframe Vertical Scrollbar
IE7 Relative/Absolute Positioning Bug with Dynamically Modified Page Content
Defining Variable Variables Using Less CSS
Differencebetween Pipe (|) and Caret (^) Attribute Selectors
How to Remove Dotted Border Around Active Hyperlinks in IE8 with CSS