angular: Problem when adding dynamically a component with g[test] selector in SVG

I’m submitting a … (check one with “x”)

[ x ] bug report [ ] feature request [ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

I try to add dynamically this component within SVG:

@Component({
  selector: 'g[test1]',
  template: `
    <svg:text x="10" y="15" fill="red">I love SVG!</svg:text>
  `
})
export class Test1Comp {
}

I use this approach:

this.resolver.resolveComponent(Test1Comp).then((factory:ComponentFactory<any>) => {
    this.cmpRef = this.viewContainerRef.createComponent(factory);
});

Whereas the corresponding content is added to the DOM, it appears that the host element (g) isn’t a valid SVG element (perhaps the svg namespace isn’t used):

<g test1> <!-- UnkownHTMLElement-->  
  <text>...</text> <!-- SVGTextElement -->
</g>

This prevents from displaying the SVG elements within the g one.

Expected/desired behavior

To be able to add dynamically components within SVG with selectors like g[test1].

Reproduction of the problem

See this plunkr: http://plnkr.co/edit/6aLGnLNi0svLk4CVS9M2?p=preview.

What is the expected behavior?

I expect the added host element to be an SVGElement and not an HTMLUnknownElement.

What is the motivation / use case for changing the behavior?

Please tell us about your environment:

  • Angular version: 2.0.0-rc.4
  • Browser: [Chrome]
  • Language: [ TypeScript ]

About this issue

  • Original URL
  • State: open
  • Created 8 years ago
  • Reactions: 16
  • Comments: 23 (5 by maintainers)

Most upvoted comments

if you have a problem with the dynamic create svg component, you can try it

let factory = this.resolver.resolveComponentFactory(MyComponent);
let groupNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
let component = factory.create(injector, [], groupNode);
this.container.insert(component.hostView);

The problem persists in 4.x

Any updates? This issue has been going on for six years

One possible workaround while this is still being worked out is to embed another svg element instead of just g. Something like this:

selector: 'svg:svg[directive]',
template: '<svg:g></svg:g>'

The problem persists in 2.0.0 final

Still an issue in Angular 7

Is there any possibility to do this dynamically instead in the method OnInit()? And is it possible to do this with different classes and more then one? Here is the link: https://stackblitz.com/edit/angular-bgsjqu?file=src%2Fapp%2Fapp.module.ts

We did an investigation and it looks like we don’t include the namespace in the selector information and it’s not persisted into the scope of the componentRef. So when we generate the hostNode we can’t apply the proper namespace. Aside from the workarounds already mentioned in this thread, another option is to pass in the native element on factory create.

export class LoaderDirective implements OnInit {
  constructor(
    private resolver: ComponentFactoryResolver,
    private injector: Injector,
    private elementRef: ElementRef
  ) {}

  ngOnInit() {
    const factory = this.resolver.resolveComponentFactory(Test1Comp);
    factory.create(this.injector, [], this.elementRef.nativeElement);
  }
}

We’ve talked about potential solutions. One is to update the selector to include the namespace so it gets applied properly on hostnode creation. Another we’ve discussed is to add another field for namespace to the componentDef for use in this case.

However, more investigation is needed.

This continues to be a problem in Angular 9.x running ivy, here is the reproduce scenario: https://stackblitz.com/edit/angular-wp8smo?file=src%2Fapp%2Fapp.module.ts

The crux of the issue here is that a dynamically created component does not specify SVG namespace for its host element created as part of component instantiation. In the linked stackblitz a user is trying to specify a namespace for the dynamically created component (svg:g[test1]) but this information is not taken into account when creating host element.

We should definitively fix this one as the current behaviour is properly confusing for the users and not easy to debug / understand.

Relevant code: https://github.com/angular/angular/blob/540c29cd6bfc4124a30f5f8e7b599d326baf6af4/packages/core/src/render3/component_ref.ts#L147-L154

@alexzuza thanks very much for the very useful hints! I’ll have a look at the problem in more details 😉