7

For the last couple of days I've been trying several answers, suggestions and tutorials for the problem, but unfortunately non of them did the trick.

The closest one was this:

https://juristr.com/blog/2019/08/dynamically-load-css-angular-cli/

But it uses "extractCss" which has been deprecated since the article has been published.

According to the article:

  1. "styles.js" file should disappear in the Inspector > Network > JS
  2. Clicking the button should add its css file in Inspector > Network > CSS

But neither of these two is happening at the moment.

app.component.ts

    const head = this.document.getElementsByTagName('head')[0];
    console.log(head);
    let themeLink = this.document.getElementById(
      'client-theme'
    ) as HTMLLinkElement;
    if (themeLink) {
      themeLink.href = styleName;
    } else {
      const style = this.document.createElement('link');
      style.id = 'client-theme';
      style.href = `${styleName}`;
      head.appendChild(style);
    }
  }

app.component.html

    <head>
    </head>
    <body>
        <button type="button" (click)="loadStyle('client-a-style.css')">STYLE 1</button> 
        <button type="button" (click)="loadStyle('client-b-style.css')">STYLE 2</button>     
    </body>
</html>

angular.json

"styles": [
              "src/styles.css",
              {
                "input": "src/client-a-style.css",
                "bundleName": "client-a",
                "inject": false
              },
              {
                "input": "src/client-b-style.css",
                "bundleName": "client-b",
                "inject": false
              }

These are the main parts of my code.

Hopefully I've explained the problem sufficiently. Thank you for helping!

3 Answers 3

10

You can put your additionals .css in the folder assets (and remove from angular.json)

Then the only change is add the "assets" folder to the href

  loadStyle(styleName: string) {
    const head = this.document.getElementsByTagName('head')[0];

    let themeLink = this.document.getElementById(
      'client-theme'
    ) as HTMLLinkElement;
    if (themeLink) {
      themeLink.href = `assets/${styleName}`; //<--add assets
    } else {
      const style = this.document.createElement('link');
      style.id = 'client-theme';
      style.rel = 'stylesheet';
      style.type = 'text/css';
      style.href = `assets/${styleName}`; //<--add assets

      head.appendChild(style);
    }
  }

a stackblitz

Sign up to request clarification or add additional context in comments.

3 Comments

your demo is amazing, thanks! will implement it in my code asap to see if it works there as well. thanks again!
SOLVED IT! thank you so much!
note that this will not work with SSR, as document does not exist on a server, and CSS script will be injected after page is rendered, and angular is initialized, making page suddenly change it's look.
5

One of possible solution to this task:

import { DOCUMENT } from '@angular/common';
import { Inject, OnDestroy, OnInit, Renderer2 } from '@angular/core';


export class MyComponent implements OnInit, OnDestroy {
  private style?: HTMLLinkElement;

  constructor(
    @Inject(DOCUMENT) private document: Document,
    private renderer2: Renderer2,
  ) {}

  public ngOnInit(): void {
    const cssPath = '/link/to/style.css';
    
    // Create a link element via Angular's renderer to avoid SSR troubles
    this.style = this.renderer2.createElement('link') as HTMLLinkElement;

    // Add the style to the head section
    this.renderer2.appendChild(this.document.head, this.style);

    // Set type of the link item and path to the css file
    this.renderer2.setProperty(this.style, 'rel', 'stylesheet');
    this.renderer2.setProperty(this.style, 'href', cssPath);
  }
  
  public ngOnDestroy(): void {
    // Don't forget to remove style after component destroying
    this.renderer2.removeChild(this.document.head, this.style);
  }
}

If and if your css-files are on the server, so you probably should update your proxy.conf.json file to have access this file from localhost while serve mode is on.

2 Comments

It works fine in a newly created angular v18 project without any issues. I implemented the same on my angular v14 project. The stylesheet appended in the head tag dynamically. But the styles not getting applied to the HTML elements. Any idea about the root of this issue ?
I would check this behaviour in any other browser. And check selectors in the css. Applying styles from appended stylesheet is native ability for browser, it should work if stylesheet added correctly.
1

I think you are missing a property in the link tag, add this to the place you create the link element and it should work.

style.rel = 'stylesheet';

2 Comments

then it creates a different error: "The stylesheet was not loaded because its MIME type..."
About the error its MIME type..., check the name of the file.css and the argument you pass (if you try to load a file.css that not exist Angular try to load the own app -the index.html-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.