neukoellnjenny
neukoellnjenny

Reputation: 180

Replace new PrimeNG Checkbox Icon dynamically at runtime with a Directive

I am looking for a work-around to replace the new Checkbox Check Icon, since angular + primeng updates the icons changed, but I want to use the older version of it.

Please find a minimal reproduction of my issue here.

My idea is to target all <p-checkbox> with a directive and replace the <checkicon> somehow.

I tried with viewContainerRef in the directives constructor, but then viewContainerRef targets the wrong html element (p-checkbox) and the icon is inserted in the wrong place.

@Directive({
  selector: 'p-checkbox',
})
export class IconDirective {
  constructor(private viewContainerRef: ViewContainerRef) {}
}

Then I tried to target PrimeNG´s checkicon element directly as that is the place I want to replace the checkicon with my custom icon, but that does not seem to work.

@Directive({
  selector: 'checkicon',
})
export class IconDirective {
  constructor(private viewContainerRef: ViewContainerRef) {}

@HostListener('click', ['$event']) onModelChange(): void {
  setTimeout(() => {
    this.replaceCheckIcon();
  });
}

  async replaceCheckIcon() {
    this.viewContainerRef.clear();
    this.viewContainerRef.createComponent(CustomIcon);
  }
}

Following options won't work for me:

  1. the newly introduced checkboxIcon property, since I use the pi pi-times icon, but this icon changed in appearance.

  2. touching / changing any html directly, because in my project there are thousand of checkboxes and I won't add the <ng-template pTemplate="icon"> with my custom icon to all checkbox occurrences.

  3. adding <ng-container #target> to any of my html to have a viewContainerRef from a ViewChild query is also not an option, tho adding it programmatically would be an option, but I could not figure it out.

Upvotes: 1

Views: 242

Answers (2)

Vagner Machado
Vagner Machado

Reputation: 1

Check the prefer icon on primeicons.css, like pi-times:

.pi-times:before {
    content: "\e90b";
}

Get content and replace default pi-check:

component:

<p-checkbox ngClass="custom-icon-check"></p-checkbox>

CSS:

::ng-deep .custom-icon-check .ui-chkbox .ui-chkbox-box .pi-check:before {
    content: "\e90b" !important;
}

Checkbox selected result

Or just:

<p-checkbox checkboxIcon="pi pi-times"/>

Upvotes: 0

Naren Murali
Naren Murali

Reputation: 56730

First you need to check if the old icon exists which I used querySelector, then I remove it using renderer2's removeChild method.

Then we can use createComponent API to create the component. Then add the default primeng classes for the icon using addClass, then finally using appendChild insert the new icon where the old icon used to be.

Hope you use this code and suit it to your requirements.

import {
  Directive,
  ElementRef,
  HostListener,
  Renderer2,
  ViewContainerRef,
  createComponent,
  Injector,
  EnvironmentInjector,
  ChangeDetectorRef,
} from '@angular/core';
import { CustomIcon } from './icon/custom-icon';

@Directive({
  selector: 'p-checkbox',
})
export class IconDirective {
  @HostListener('click', ['$event']) onModelChange(): void {
    setTimeout(() => {
      this.replaceCheckIcon();
    });
  }

  constructor(
    private elementRef: ElementRef,
    private viewContainerRef: ViewContainerRef,
    private renderer: Renderer2,
    private environmentInjector: EnvironmentInjector,
    private cdr: ChangeDetectorRef
  ) {}

  replaceCheckIcon() {
    const oldIcon = this.elementRef.nativeElement.querySelector('checkicon');
    const newIcon = this.elementRef.nativeElement.querySelector('custom-icon');
    const checkboxContainer =
      this.elementRef.nativeElement.querySelector('.p-checkbox-box');
    if (oldIcon) {
      this.renderer.removeChild(this.elementRef.nativeElement, oldIcon);
    }
    if (!newIcon) {
      const component = createComponent(CustomIcon, {
        environmentInjector: this.environmentInjector,
      });
      this.renderer.addClass(component.location.nativeElement, 'p-element');
      this.renderer.addClass(
        component.location.nativeElement,
        'p-icon-wrapper'
      );
      this.renderer.appendChild(
        checkboxContainer,
        component.location.nativeElement
      );
    }
  }
}

Stackblitz Demo

Upvotes: 1

Related Questions