Kushagra Agarwal
Kushagra Agarwal

Reputation: 11

Render2 not working in Angular basic project

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

Answers (1)

Naren Murali
Naren Murali

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 = [];
  }
}

stackblitz

Upvotes: 0

Related Questions