I want to load a specific CSS file only when a user accesses the contact.html
view on my AngularJS app/site. I found this answer which almost made sense to me How to include view/partial specific styling in AngularJS The accepted answer by charlietfl reads :
Could append a new stylesheet to head within $routeProvider
. For
simplicity am using a string but could create new link element also,
or create a service for stylesheets
/* check if already exists first - note ID used on link element*/
/* could also track within scope object*/
if( !angular.element('link#myViewName').length){
angular.element('head').append('<link id="myViewName" href="myViewName.css" rel="stylesheet">');
}
Biggest benefit of prelaoding in page is any background images will
already exist, and less lieklyhood of FOUC
The problem is that I do not know exactly where in my $routeProvider
to add the code. charlietfl mentions where to put it in a comment which reads
not if the when for the route hasn't been called. Can put this code in
controller callback of when within the routeProvider, or perhaps
within resolve callback which likely triggers sooner
I have modified my $routeProvider
following the advice. I added a resolve
in the object following .when('/contact'
. Here is my code
angular.module('maxmythicApp', ['ngResponsiveImages'])
.config(function ($locationProvider, $routeProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix = '!';
$routeProvider
.when('/', {
templateUrl: '/views/design.html',
controller: 'MainCtrl'
})
.when('/design', {
templateUrl: '/views/design.html',
controller: 'MainCtrl'
})
.when('/about', {
templateUrl: '/views/about.html',
controller: 'MainCtrl'
})
.when('/contact', {
templateUrl: '/views/contact.html',
controller: 'MainCtrl',
resolve:
if( !angular.element('link#myViewName').length){
angular.element('head').append('<link id="myViewName" href="myViewName.css" rel="stylesheet">');
}
})
.otherwise({
redirectTo: '/'
});
});
Would this work?
I made a service for it.
Important part of the code :
var head = angular.element(document.querySelector('head')); // TO make the code IE < 8 compatible, include jQuery in your page and replace "angular.element(document.querySelector('head'))" by "angular.element('head')"
if(head.scope().injectedStylesheets === undefined)
{
head.scope().injectedStylesheets = [];
head.append($compile("<link data-ng-repeat='stylesheet in injectedStylesheets' data-ng-href='{{stylesheet.href}}' rel='stylesheet' />")(scope)); // Found here : http://stackoverflow.com/a/11913182/1662766
}
head.scope().injectedStylesheets.push({href: "/url/to/style.css"});
Full code in Github : https://github.com/Yappli/angular-css-injector)
UPDATED: Here is the solution to inject(load) a specific CSS using the $routeProvider.
The solution described below is an alternative to apply different classes and page title based on the route which could be used in other situations.
For each route I've created a new key called 'bodyClass' and 'title' (but you could called anything you like it) and it looks like this:
'use strict';
var myApp = angular.module('myApp', 'ngResource'])
.config(function ($routeProvider) {
myApp.siteName = 'My Cool App';
$routeProvider
.when('/home', {
title:'Home - ' + myApp.siteName,
bodyClass: 'home',
templateUrl: 'views/home.html',
controler: 'bmsHomeCtrl'
})
.when('/contact', {
title:'Contact - ' + myApp.siteName,
bodyClass: 'contact',
templateUrl: 'views/contact.html',
controler: 'bmsContactCtrl'
})
.otherwise({
redirectTo: '/home'
});
});
Then for each $routeChangeSuccess event I change the <title>
of the page and also the class of the <body>
.
myApp.run(['$location', '$rootScope', function($location, $rootScope) {
$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
if (current.$$route) {
$rootScope.title = current.$$route.title;
$rootScope.bodyClass = current.$$route.bodyClass;
}
});
}]);
You put the code above on the same main app.js (for example) file.
On my index.html page, which renders the views, I have the following codes to pick up the title and class:
<title>{{ title }}</title>
<body class="{{ bodyClass }}">
So if i visit the home page of my application the title tag will be
<tittle> Home - My Cool App</tittle>
and the body tag will be
<body class="home">
It's working like a charm.
I know this solution doesn't load a CSS file, but you could put those styles inside a '.contact' class that is applied only when you hit a specific route.
Not sure if solves your problem but I hope that helps or at least point you on the right direction.
For a full solution I suggest using AngularCSS.
As you already know, in Angular we can include templates (structure) and controllers (behavior) in pages and components. AngularCSS enables the last missing piece: attaching stylesheets (presentation).
Routes example:
$routeProvider
.when('/page1', {
templateUrl: 'page1/page1.html',
controller: 'page1Ctrl',
/* Now you can bind css to routes */
css: 'page1/page1.css'
})
.when('/page2', {
templateUrl: 'page2/page2.html',
controller: 'page2Ctrl',
/* You can also enable features like bust cache, persist and preload */
css: {
href: 'page2/page2.css',
bustCache: true
}
})
.when('/page3', {
templateUrl: 'page3/page3.html',
controller: 'page3Ctrl',
/* This is how you can include multiple stylesheets */
css: ['page3/page3.css','page3/page3-2.css']
})
.when('/page4', {
templateUrl: 'page4/page4.html',
controller: 'page4Ctrl',
css: [
{
href: 'page4/page4.css',
persist: true
}, {
href: 'page4/page4.mobile.css',
/* Media Query support via window.matchMedia API
* This will only add the stylesheet if the breakpoint matches */
media: 'screen and (max-width : 768px)'
}, {
href: 'page4/page4.print.css',
media: 'print'
}
]
});
Directive example:
myApp.directive('myDirective', function () {
return {
restrict: 'E',
templateUrl: 'my-directive/my-directive.html',
css: 'my-directive/my-directive.css'
}
});
You can read more about AngularCSS here:
http://door3.com/insights/introducing-angularcss-css-demand-angularjs
I think the best/simplest answer is one I left here. Someone else asked the same question, so I came up with some simple code and a small github repo to handle this scenario.