У меня есть компонент, который отображает DOM, который должен находиться внутри тега svg:
import { Component, Input } from '@angular/core';
@Component({
selector: 'g[hello]',
template: `<svg:text x = "50%" y = "50%" text-anchor = "middle">Hello, {{name}}</svg:text>`,
styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent {
@Input() name: string;
}
Когда я создаю его статически, все работает нормально (текст виден на странице):
<svg>
<svg:g hello name = "Static component"></svg:g>
</svg>
Генерируется следующий DOM:
<svg _ngcontent-iej-c129 = "">
<g _ngcontent-iej-c129 = "" hello = "" name = "Static component" _nghost-iej-c130 = "" ng-reflect-name = "Static component">
<text _ngcontent-iej-c130 = "" text-anchor = "middle" x = "50%" y = "50%">
Hello, Static component
</text>
</g>
</svg>
Проблема начинается, когда я пытаюсь создать экземпляр компонента динамически, используя ComponentFactoryResolver:
<svg>
<ng-container #container></ng-container>
</svg>
import { Component, ViewChild, ViewContainerRef, ComponentFactoryResolver, OnInit } from '@angular/core';
import { HelloComponent } from './hello.component'
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
@ViewChild('container', {read: ViewContainerRef, static: true}) container: ViewContainerRef;
constructor(private componentFactoryResolver: ComponentFactoryResolver) {
}
ngOnInit() {
// Instantiating HelloComponent dynamically
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(HelloComponent)
const componentRef = this.container.createComponent(componentFactory);
componentRef.instance.name = 'Dynamic component'
}
}
Созданный DOM выглядит нормально, но по какой-то причине текст не виден на странице:
<svg _ngcontent-iej-c129 = "">
<!---->
<g hello = "" _nghost-iej-c130 = "">
<text _ngcontent-iej-c130 = "" text-anchor = "middle" x = "50%" y = "50%">
Hello, Dynamic component
</text>
</g>
</svg>






Я предполагаю, что здесь есть два вопроса:
Ответ на первый вопрос заключается в использовании svg вместо g для группировки элементов.
В вашем конкретном примере это будет означать изменение селектора:
@Component({
selector: 'svg[hello]',
template: `<svg:text x = "50%" y = "50%" text-anchor = "middle">Hello, {{name}}</svg:text>`,
styles: [`h1 { font-family: Lato; }`]
})
И app.component.html:
<svg>
<svg hello name = "Static component"></svg>
</svg>
svg против группыТеперь давайте перейдем ко второму вопросу. Почему это происходит?
Ваш селектор не содержит пространства имен svg. Для правильного отображения селектор должен быть svg:g[hello].
Но это невозможно из-за старой проблемы, которая существует со времен Angular 5.
Подробнее здесь и здесь.
Как упоминалось в комментарии это, основная проблема здесь заключается в том, что селектор Angular не может содержать пространство имен для создания элемента.
Селектор svg:g[hello] будет преобразован в g[hello], в результате чего Angular будет использовать document.createElement вместо document.createElementNS для создания нового элемента.
Почему использование svg[hello] работает?
Потому что если мы используем селектор svg[hello], то он анализируется на <svg child> и для этого тега Angular равен предоставление пространства имен неявно:
'svg': new HtmlTagDefinition({implicitNamespacePrefix: 'svg'}),
Кажется, это связано со старой проблемой Angular: №10404, а также с проблемой, упомянутой Виталием: #20337
В №10404ДинВейчжэ предлагает следующий обходной путь:
Вместо этого кода:
const componentRef = this.container.createComponent(componentFactory);
Чтобы использовать это:
const groupElement = document.createElementNS("http://www.w3.org/2000/svg", "g");
const componentRef = componentFactory.create(injector, [], groupElement);
this.container.insert(componentRef.hostView)
Это изменение решает проблему без замены <g> на <svg>. Принятый ответ, конечно же, также решает проблему, но у меня есть некоторые опасения по поводу потери производительности, которая может привести к такой замене.
Рабочий стек-блиц: здесь
Я оставил заметку в выпуске github.
Спасибо, что указали на эту проблему. Я также недавно нашел еще один, который также кажется связанным: github.com/angular/angular/issues/10404