简体   繁体   中英

Angular and SVG: how to dynamically load SVG components?

in the app that I am developing I have a list of commands (GC->circle, GB->box, GE->ellipse, etc). I have to render them in a SVG.

I followed the guide https://angular.io/guide/dynamic-component-loader but there's something that I am missing about SVGs.

I prepared a component for each command (it already sounds dumb because the code is the same except for the template):

@Component({
  selector: '[app-gc]',
  template: '<svg:circle [attr.r]="command.diameter/2" [attr.stroke]="command.borderColor" fill="#000" [attr.stroke-width]="command.borderThickness" />'
})
export class GCComponent implements OnInit, SVGComponent {
  @Input('[command]') command: ZPL2.GraphicShapeBase;
  constructor() { }
}

The component on which I load the rendered command looks like this:

@Component({
  selector: '[draggableSVGItem]',
  template: '<svg:g svg-host/>'
})
export class DraggableSvgItemComponent implements OnInit {      
  x: number = 0;
  y: number = 0;
  command: ZPL2.GraphicShapeBase;

  @Input()
  set draggableSVGItem(graphicCommand: ZPL2.GraphicShapeBase) {
    this.command = graphicCommand;
    this.x = graphicCommand.x;
    this.y = graphicCommand.y;
  }
  constructor() { }

  ngOnInit() {
    // Get the appropriate component for the command
    var componentType = null;
    if (this.command instanceof ZPL2.GC) {
      componentType = GCComponent;
    }
    if (this.command instanceof ZPL2.GB) {
      componentType = GBComponent;
    }
    if (this.command instanceof ZPL2.GE) {
      componentType = GEComponent;
    }

    // Get the component factory
    let componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentType);

    // Clear the host view
    let viewContainerRef = this.svgHost.viewContainerRef;
    viewContainerRef.clear();

    // Dynamically create the component and set its command as the current one
    let componentRef = viewContainerRef.createComponent(componentFactory,);
    (<SVGComponent>componentRef.instance).command = this.command;
  }
}

Everything works almost perfectly. The problem I have is that the component creation enclose the SVG elements into a DIV and consequently the output is blank:

额外的div

I'm new to Angular, do you have any suggestion to get rid of that DIV and to make the code simpler?

EDIT

I solved it following the example at this link: https://www.chrisjmendez.com/2017/06/17/angular-dynamically-inserting-svg-into-an-element/

By binding the innerHTML property of the element I can set a different SVG content depending on the command class type:

template: <svg:g [innerHTML]="svg"/>

ngOnInit() {
  // Get the appropriate component for the command
  var html = ``;
  if (this.command instanceof ZPL2.GC) {
    html = `<circle r="` + this.command.diameter / 2 + `" stroke="` + this.command.borderColor + `" fill="#000" stroke-width="` + this.command.borderThickness + `" />`;
  }
  if (this.command instanceof ...

  this.svg = this.sanitizer.bypassSecurityTrustHtml(html);
}

In this way I don't need to create a component for each command. Each command can have its own getHTML() method.

The drawback is that I have no binding with the command's properties, right?

My Solution for load dynamically svg file (for the same component):

In .html template (I implemented that with drop-down list, but here I cut the code for the example):

<object *ngIf="currentSVG" type="image/svg+xml" [data]="SVGFile"></object>

In .ts file:

import { DomSanitizer, SafeUrl } from '@angular/platform-browser';

//component and class definition

SVGFile: SafeUrl;
currentSVG: string;

constructor(protected sanitizer: DomSanitizer) { ... }

//your code  

this.currentSVG = True;
this.SVGFile = this.sanitizer.bypassSecurityTrustResourceUrl('<your SVG file path>');

Note: SVG files should be located in assets directory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM