Search code examples
angulartypescriptsvg

Can we render Angular components inside of our SVG templates?


Seeing that we can save our template files as .svg rather than .html now I figured I could make svg components that could be used as follows.

main.component.svg

<svg>
    <my-svg-component></my-svg-component>
</svg>

mySvg.component.svg

<text x="0" y="60">test text</text>

I got an error saying <text></text> wasn't a recognized element so I modified it to this

<svg:text x="0" y="65">test text</svg:text>

The error went away however nothing is rendering. I added the script directly into the <svg> tag in the main.component.svg file without the svg: at the beginning and it worked fine.

Is there something I should be doing in the mySvg.component template to make this work as a reusable component or do we have to generate all the SVG inside one template?

UPDATE

I tried using SVG's <foreignObject> like so

<svg>
    <foreignObject>
        <my-svg-component></my-svg-component>
    </foreignObject>
<svg>

this didn't work either. I tested it out with a paragraph tag and noticed I had to use <xhtml:p> in order for it to render. I tried adding the xhmtl: part to my component for grins and giggles and still didn't see anything render. Now I'm wondering if there's an angular: of some form that can be used.


Solution

  • You could do that this way:

    template:

    <svg>
      <g svgtext></g>
    </svg>
    

    svg component:

    import { Component } from '@angular/core';
    
    @Component({
      selector: '[svgtext]',
      template: `<svg:text x="0" y="65">test text</svg:text>`,
      styles: [`your styles come here`]
    })
    export class HelloComponent  {
    
    }
    

    So the trick is to attach your svg component to another svg element (group - g) via attribute selector. This way resulting template is valid SVG and you can get your text rendered.

    See here: https://stackblitz.com/edit/angular-fd1tcd

    If you do component selector with tags, than SVG schmema is broken and browser won't be able to render SVG. Using group (which is a valid svg container) we avoid that issue and the additional component html gets injected right inside such a group.

    You can read this fantastic article by Tero (pretty old now) for more insights: https://teropa.info/blog/2016/12/12/graphics-in-angular-2.html