29

Is it possible to dynamically inject urls to stylesheets into a component?

Something like:

styleUrls: [
  'stylesheet1.css',
  this.additionalUrls
]

or (wishful thinking and note that this is just fake code):

export class MyComponent implements dynamicUrls {

  ngDynamicUrls() {
    this.inject(['anotherStylesheet.css', 'anotherStylesheet2.css']);
  }
}

Because if you're gonna be able to override certain styles from stylesheet1 without having access to it, how are you supposed to do that? My only idea is to have dynamic styleUrls somehow but I don't think this is even possible from what I could find.

Any ideas?

Chrillewoodz
  • 27,055
  • 21
  • 92
  • 175

5 Answers5

9

It's possible in some maybe hack way it worked for me. You can manipulate Angular 2 Component decorator, create your own and return Angular's decorator with your properties.

  import { Component } from '@angular/core';

    export interface IComponent {
      selector: string;
      template?: string;
      templateUrl?: string;
      styles?: string[];
      styleUrls?: string[];
      directives?: any;
      providers?: any;
      encapsulation?: number;
    }

    export function CustomComponent( properties: IComponent): Function {
      let aditionalStyles: string;

      try {
          aditionalStyles =  require(`path to aditional styles/${ properties.selector }/style/${        properties.selector }.${ GAME }.scss`);
          properties.styles.push(aditionalStyles);
        } catch (err) {
          console.warn(err)
        }
      }

      return Component( properties );
    }

And in your component replace default angular 2 @Component with new one.

import { CustomComponent } from 'path to CustomComponent';

@CustomComponent({
  selector: 'home',
  templateUrl: './template/home.template.html',
  styleUrls: [ './style/home.style.scss']
})
export class ......
Virge
  • 91
  • 1
  • 5
  • Have you tested this? – Chrillewoodz Sep 29 '16 at 07:31
  • Yes this works fine for me. I'm using webpack and Angular 2.0.0 – Virge Sep 29 '16 at 10:54
  • So @Chrillewoodz did you try it too? Thinking of using this implementation but might just create a new component for each style and reference the same templateUrl and import all the script from a 3rd module... – Methodician Dec 09 '16 at 21:53
  • yeah but you still need to create a component pre style that needs to be used, it's not one component that receives a style name from the server for instance, not really dynamic – Phil May 19 '17 at 09:23
  • you put there an extra bracket and that GAME var which is not declared ! – Alex Oct 27 '17 at 06:35
7

I have found a solution:
1. I have changed the styleurls to styles in the component decorator.
2. I will get my variable.
3. I will use the require command in my decorator.

import { Component } from '@angular/core';
import { environment } from '../environments/environment';
let lang = environment['lang'];

@Component({
   selector: 'app',
   templateUrl: './app.component.html',
   styles: [require('./app.component.css'), require('./app.component.' + lang + '.css')]
  })

  export class AppComponent {

   constructor() { }

  }

In this basic example I have imported the environment variable and changed the css string dynamically.

noah lubko
  • 99
  • 2
  • 10
  • This is my first answer is stackoverflow. I don't understand why the answer is not good. Can you please explain? @Jean-FrançoisCorbett – noah lubko Aug 28 '18 at 10:48
  • I apologize! That comment & flag were meant for another answer, and apparently I somehow put them here. Please disregard! Your answer is just fine! I'm not sure where I was looking. Apologies again. – Jean-François Corbett Aug 28 '18 at 13:56
  • 3
    @noahlubko Have you tried it with production? I don't think it will work with AOT compiler. – Bharat Choudhary Mar 26 '20 at 07:24
  • This definitely does not work with the `require` one step removed. I made a module with a base component class, and it also includes `export const BASE_COMPONENT_STYLE = require("./base.component.css")`. If I try to make a subclass with `styles: [BASE_COMPONENT_STYLE]`, Ivy complains with "Unable to evaluate this expression statically" -- it isn't able to resolve the CSS *during compilation*. – Coderer Sep 28 '20 at 10:42
  • Did it here but I'm getting the following error: styleUrls must be an array of strings. Any suggestions my friends? – Andre Jan 24 '23 at 19:46
1

I used to have the same need to dynamically inject urls to stylesheets and eventually ended to initialize a component for each variable css (in my case 3 differents styles) with empty template and use them in my app component with ngIf condition.

Thanks to the use of property "encapsulation: ViewEncapsulation.None", the style of the selected component is then added to the header of the page and enable to get the correct renderer for the whole page.

0

I don't think you can have dynamic stylesheet URLs, because you cannot access your class property or method inside @Component decorator.

But you can achieve your goal by having dynamic style classes in your template.

siva636
  • 16,109
  • 23
  • 97
  • 135
  • Problem is that I won't have access to the templates, only to the components themselves. – Chrillewoodz Apr 10 '16 at 16:22
  • Well, if you can't access the template & still want to have different styles, why not consider making different components with the same template (with different style sheets) & load the components dynamically. – siva636 Apr 10 '16 at 16:35
  • That would be an option, but it still doesn't provide full personal customizing. Seems like such a functional hole that them really need to address.. – Chrillewoodz Apr 10 '16 at 16:45
  • Dynamic style classes means css overhead instead of taking advantage of sass variables. For each new skin you will be repeating the entire stylesheet. – Rohit Rane Jun 22 '17 at 06:24
-1

I used the stylesheet link in the html template with ngIf condition, it worked for me.

<link rel='stylesheet' href="/stylesheets/classicTheme.css" *ngIf="theme === 'classic' " />
<link rel='stylesheet' href="/stylesheets/styleTheme.css" *ngIf="theme === 'style' " />
vierc
  • 17
  • Just curious how this can actually work? with Angular 2, the "app" runs inside the _root_ element (usually lives under ``). So, how can your code bind to the `theme` variable? – Eric Liprandi Nov 15 '16 at 22:41
  • does not override styles for components – Phil May 19 '17 at 09:17
  • 2
    Not saying it will or won't work, but while everyone is thinking his won't work because of where the app runs, the app can change the page title, right? There must be _some_ access to the `` section. – Tim Hobbs Jul 13 '17 at 19:21