Search code examples
angularangular-universal

Angular Universal / SSR nativeElement.innerHTML and renderer.setProperty throws Error: NotYetImplemented


I have below component to render svg icons:

Component

import { ChangeDetectionStrategy, Component, ElementRef, Input, ViewChild } from '@angular/core';

@Component({
  selector: 'icon-svg',
  templateUrl: './icon-svg.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class IconSVGComponent {
  @ViewChild('svgElement', { static: false }) svgElement: ElementRef;

  @Input() icon: string;
  @Input() fill: string = 'currentColor';
  @Input() width: number = null;
  @Input() height: number = null;
  @Input() alt: string;

  public svg: string;

  public viewBox = "0 0 24 24";

  constructor() {
  }

  ngOnInit() {
    let icons = {
      'business': { value: '<path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z" />' },
      'person': { value: '<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />' },
      'menu': { value: '<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" />' },
      'search': { value: '<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" />' },
      'close': { value: '<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />' }
    };

    let icon = icons[this.icon].value;
    if (icon) {
      this.svg = icon;
      if (this.icon == 'facebook' || this.icon == 'linkedin' || this.icon == 'twitter' || this.icon == 'whatsapp') {
        this.viewBox = "0 0 512 512";
      }
    }
  }

  ngAfterViewInit() {
    this.svgElement.nativeElement.innerHTML = this.svg;
  }
}

Template

<svg xmlns="http://www.w3.org/2000/svg" [attr.fill]="fill" [attr.viewBox]="viewBox" [attr.width]="width" [attr.height]="height" class="svg-icon" #svgElement>
</svg>

This works fine in browser but throws below error in Angular Universal/SSR.

Error: NotYetImplemented
    at Element.Wo4J.exports.nyi (D:\ClientApp\dist-server\main.js:1:1616260)
    at IconSVGComponent.ngAfterViewInit (D:\ClientApp\dist-server\main.js:1:3046674)

I have also tried it with renderer.setProperty, but even that doesnt work and throws below error:

Error: NotYetImplemented
    at Element.Wo4J.exports.nyi (D:\ClientApp\dist-server\main.js:1:1616260)
    at platform_server_DefaultServerRenderer2.setProperty (D:\ClientApp\dist-server\main.js:1:1264487)
    at BaseAnimationRenderer.setProperty (D:\ClientApp\dist-server\main.js:1:1527203)
    at IconSVGComponent.ngAfterViewInit (D:\ClientApp\dist-server\main.js:1:3046680)

Can anyone please guide how to fix this and make it work on server/ssr?


Solution

  • This is related to the Domino which doesn’t implement innerHTML setter.

    https://github.com/fgnass/domino/blob/12a5f67136a0ac10e3fa1649b8787ba3b309e9a7/lib/Element.js#L95

    The simplest way to fix this is either by having the svgs defined in css class or svg as assets files and swap either the url or css class to change the icon from the component.