Reputation: 11
I have an angular application angular-tour-of-heroes with the following structure:
src
->app
->your-component
->your-component.component.html
->your-component.component.less
->your-component.component.ts
->default.less
->custom.less
->app.component.html
->app.component.ts
->app.module.ts
->app-routing.module.ts
->style-manager.service.ts
Now I will share the files:
app.component.html
<app-your-component></app-your-component>
app.module.ts
// src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { YourComponent } from './your-component/your-component.component';
@NgModule({
declarations: [
AppComponent,
YourComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
angular.json
{
"styles": [
"src/styles.less",
"src/app/your-component/default.less",
"src/app/your-component/custom.less"]
}
style-manager.service.ts
// src/app/common_modules/common_services/style-manager.service.ts
import { Injectable, Renderer2, RendererFactory2 } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class StyleManagerService {
private renderer: Renderer2;
private addedStylesheets: HTMLLinkElement[] = [];
constructor(rendererFactory: RendererFactory2) {
this.renderer = rendererFactory.createRenderer(null, null);
}
addStylesheets(links: string[]) {
links.forEach(link => {
const styleLink = this.renderer.createElement('link');
this.renderer.setAttribute(styleLink, 'rel', 'stylesheet');
this.renderer.setAttribute(styleLink, 'type', 'text/css');
this.renderer.setAttribute(styleLink, 'href', 'custom.less');
this.renderer.setAttribute(styleLink, 'app-dynamic-style', 'true');
this.renderer.appendChild(document.head, styleLink);
this.addedStylesheets.push(styleLink);
});
}
removeStylesheets() {
// Remove all dynamically added style elements
this.addedStylesheets.forEach(link => {
this.renderer.removeChild(document.head, link);
});
this.addedStylesheets = [];
}
}
your-component.component.ts
// src/app/your-component/your-component.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { StyleManagerService } from '../style-manager.service';
@Component({
selector: 'app-your-component',
templateUrl: './your-component.component.html',
styleUrls: ['./default.less'] // Use default styles by default
})
export class YourComponent implements OnInit, OnDestroy {
constructor(private styleManager: StyleManagerService) {}
ngOnInit() {
// Some condition to determine which Less file to load
const condition = true; // Change this condition as needed
if (condition) {
// Load custom Less file
this.styleManager.addStylesheets(['./your-component/custom.less']);
}
}
ngOnDestroy() {
// Remove dynamically added stylesheets when the component is destroyed
this.styleManager.removeStylesheets();
}
}
your-component.html
<p>your-component works!</p>
default.less
p{
color: aqua;
}
custom.less
p{
color: yellow;
}
I tried the above code and post that when I do ng serve I am getting 404 error for the custom.less file. Can someone help me as to what and where am I doing wrong
Upvotes: 1
Views: 159
Reputation: 58334
You can place your css files in the assets folder and then the code will work fine, please find below a working example!
html
<select [(ngModel)]="style" (ngModelChange)="setStyleSheet()">
<option [value]="'../assets/qwerty.css'">qwerty</option>
<option [value]="'../assets/custom.css'">custom</option>
<option [value]="'../assets/zxcv.css'">zxcv</option>
</select>
<p class="test">your-component works!</p>
ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { StyleManagerService } from '../style-manager.service';
@Component({
selector: 'app-your-component',
templateUrl: './your-component.component.html',
standalone: true,
imports: [FormsModule],
styleUrls: ['../assets/default.css'], // Use default styles by default
})
export class YourComponent implements OnInit, OnDestroy {
style = '../assets/default.css';
constructor(private styleManager: StyleManagerService) {}
ngOnInit() {}
setStyleSheet() {
if (this.style) {
// Load custom Less file
this.styleManager.addStylesheets([this.style]);
}
}
ngOnDestroy() {
// Remove dynamically added stylesheets when the component is destroyed
this.styleManager.removeStylesheets();
}
}
service
// src/app/common_modules/common_services/style-manager.service.ts
import { Injectable, Renderer2, RendererFactory2 } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class StyleManagerService {
private renderer: Renderer2;
private addedStylesheets: HTMLLinkElement[] = [];
constructor(rendererFactory: RendererFactory2) {
this.renderer = rendererFactory.createRenderer(null, null);
}
addStylesheets(links: string[]) {
links.forEach((link) => {
if (this.addStylesheets.length) {
this.addedStylesheets.forEach((link: any) => {
this.renderer.removeChild(document.head, link);
});
this.addedStylesheets = [];
}
const styleLink = this.renderer.createElement('link');
this.renderer.setAttribute(styleLink, 'rel', 'stylesheet');
this.renderer.setAttribute(styleLink, 'type', 'text/css');
this.renderer.setAttribute(styleLink, 'href', link);
this.renderer.setAttribute(styleLink, 'app-dynamic-style', 'true');
this.renderer.appendChild(document.head, styleLink);
this.addedStylesheets.push(styleLink);
});
}
removeStylesheets() {
// Remove all dynamically added style elements
this.addedStylesheets.forEach((link) => {
this.renderer.removeChild(document.head, link);
});
this.addedStylesheets = [];
}
}
Upvotes: 0