Angular: Using ComponentFactoryResolver for dynamic instantiation of the components, rendering inside SVG
I assume there are two questions here:
- How to make it work?
- Why is that happening?
The answer to the first question is using svg
instead of g
for grouping elements.
In your concrete example it would mean changing the selector:
@Component({
selector: 'svg[hello]',
template: `<svg:text x="50%" y="50%" text-anchor="middle">Hello, {{name}}</svg:text>`,
styles: [`h1 { font-family: Lato; }`]
})
And app.component.html
:
<svg>
<svg hello name="Static component"></svg>
</svg>
- Working StackBlitz
- Nested
svg
vs group
Now let's get to the second question. Why is this happening?
Your selector doesn't contain svg
namespace. In order to render it correctly the selector should be svg:g[hello]
.
But that is impossible due to an old issue that's been there since Angular 5.
More details here and here.
As mentioned in this comment the main issue here is that Angular selector cannot contain namespace for creating element.
Selector svg:g[hello]
will be parsed to g[hello]
, as a result Angular will use document.createElement
instead of document.createElementNS
to create new element.
Why using svg[hello]
works?
Because if we use selector svg[hello]
then it is parsed to <svg child>
and for this tag Angular is providing namespace implicitly:
'svg': new HtmlTagDefinition({implicitNamespacePrefix: 'svg'}),
Seems to be related to the old Angular issue: #10404, and also to the issue, mentioned by Vitalii: #20337
In #10404, DingWeizhe suggests the following work around:
Instead of this code:
const componentRef = this.container.createComponent(componentFactory);
To use this:
const groupElement = document.createElementNS("http://www.w3.org/2000/svg", "g");
const componentRef = componentFactory.create(injector, [], groupElement);
this.container.insert(componentRef.hostView)
This change solves the problem without replacing <g>
with <svg>
. An accepted answer, of course, also solves the problem, but I have some concern about performance penalty, which could cause such replacement.
Working stackblitz is here
Seems that it is related to the open issue, see
https://github.com/angular/angular/issues/20337