Search code examples
angulartypescriptprimengbackground-colorstyling

How to change the background of PrimeNG's p-card component after ngAfterViewInit?


I would like to update the background of a p-card (PrimeNG component) AFTER initializing the view.

My real need: I have an image in a p-card, I would like to retrieve the dominant color of an image and set it as the background color of the p-card component

.html side:

<p-card [style]="{'background': dominantColor}">
  <img src="path_to/image.png" #image />
</p-card>

.ts side:

  @ViewChild('image') imageElement: ElementRef | undefined;
  dominantColor: string = '#000000';

ngAfterViewInit(): void {
    const img = this.imageElement!.nativeElement;

    img.onload = () => {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      canvas.width = img.width;
      canvas.height = img.height;
      ctx!.drawImage(img, 0, 0, img.width, img.height);
      const imageData = ctx!.getImageData(0, 0, img.width, img.height);
      const data = imageData.data;

      let red = 0;
      let green = 0;
      let blue = 0;

      for (let i = 0; i < data.length; i += 4) {
        red += data[i];
        green += data[i + 1];
        blue += data[i + 2];
      }

      red = Math.round(red / (data.length / 4));
      green = Math.round(green / (data.length / 4));
      blue = Math.round(blue / (data.length / 4));

      this.dominantColor = this.rgbToHex(red, green, blue);
    };
  }

  rgbToHex(r: number, g: number, b: number): string {
    return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
  }

Unfortunately, only the default value is taken into account and not the new value obtained...

I have already seen this topic:
how to style dynamically assign background to p-card of primeng?
and tried the solution but without success, and as my need is a bit specific I took the liberty of creating this question Thank you in advance for your help


Update: Trying @Ricudo solution, didn't solved yet: Html code:

<p-card [style]="cardStyle">
  <img src="assets/img/default/recipe-image.png" #image />
</p-card>

Ts code:

cardStyle = { background: '#000000' };

  ngAfterViewInit(): void {
    const img = this.imageElement!.nativeElement;

    img.onload = () => {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      canvas.width = img.width;
      canvas.height = img.height;
      ctx!.drawImage(img, 0, 0, img.width, img.height);

      const imageData = ctx!.getImageData(0, 0, img.width, img.height);
      const data = imageData.data;

      let red = 0;
      let green = 0;
      let blue = 0;

      for (let i = 0; i < data.length; i += 4) {
        red += data[i];
        green += data[i + 1];
        blue += data[i + 2];
      }

      red = Math.round(red / (data.length / 4));
      green = Math.round(green / (data.length / 4));
      blue = Math.round(blue / (data.length / 4));

      this.cardStyle = { background: this.rgbToHex(red, green, blue) };
    };
  }

Solution

  • As you can see you pass an object as style to primeNg. It is right option because primeNG expects object. The problem is with change detection. You change the property of the passed object, but not the object itself, so change detection is not triggered and color is not changed. Just change dominantColor: string = '#000000'; to cardStyle = {dominantColor: '#000000'}; and then instead on this.dominantColor = this.rgbToHex(red, green, blue); use this.cardStyle = {dominantColor: this.rgbToHex(red, green, blue)};. And of .html substitute [style]="{'background': dominantColor}" with [style]="cardStyle". Now the problem might be solved.