Angular2:在DOM中将动态组件作为容器的子代插入 [英] Angular2: Insert a dynamic component as child of a container in the DOM
问题描述
是否有一种方法可以动态地将组件作为Angular 2中DOM标签的子(不是同级)插入?
Is there a way to insert dynamically a component as a child (not a sibling) of a DOM tag in Angular 2?
周围有很多示例可以插入动态组件作为给定<c0>标记的同级,例如(从RC3开始):
There are plenty of examples around there to insert a dynamic component as a sibling of a given ViewContainerRef
's tag, like (as of RC3):
@Component({
selector: '...',
template: '<div #placeholder></div>'
})
export class SomeComponent {
@ViewChild('placeholder', {read: ViewContainerRef}) placeholder;
constructor(private componentResolver: ComponentResolver) {}
ngAfterViewInit() {
this.componentResolver.resolveComponent(MyDynamicComponent).then((factory) => {
this.componentRef = this.placeholder.createComponent(factory);
});
}
}
但这会生成一个类似于以下内容的DOM:
But this generates a DOM similar to:
<div></div>
<my-dynamic-component></my-dynamic-component>
预期结果:
<div>
<my-dynamic-component></my-dynamic-component>
</div>
使用SomeComponent
的ViewContainerRef
具有相同的结果,它仍将生成的组件作为同级而不是子级插入.对于模板为空并且将动态组件插入模板(在组件选择器标记内)的解决方案,我会没事的.
Using the SomeComponent
's ViewContainerRef
has the same result, it is still inserting the generated component as a sibling, not a child. I would be okay with a solution where the template is empty and dynamic components are inserted in the template (within the component selector tag).
使用ng2-dragula之类的库从动态组件列表中拖动时,DOM结构非常重要,并且从模型更新中受益.额外的div在可拖动元素的列表中,但在模型外部,这破坏了拖放操作.放下逻辑.
The DOM structure is very important when using libraries like ng2-dragula to drag from a list of dynamic components and benefit from the model updates. The extra div is in the list of draggable elements, but outside the model, breaking the drag & drop logic.
有人说这是不可能的(评论),但这听起来像是一个非常令人惊讶的限制.
Some say it is not possible (c.f. this comment), but it sounds like a very surprising limitation.
推荐答案
TL; DR :将<div #placeholder></div>
替换为<div><ng-template #placeholder></ng-template></div>
以插入div
内.
TL;DR: replace <div #placeholder></div>
with <div><ng-template #placeholder></ng-template></div>
to insert inside the div
.
这是一个有效的stackblitz示例 (角度6),以及相关代码:
Here is a working stackblitz example (Angular 6), and the relevant code:
@Component({
selector: 'my-app',
template: `<div><ng-template #container></ng-template></div>`
})
export class AppComponent implements OnInit {
@ViewChild('container', {read: ViewContainerRef}) viewContainer: ViewContainerRef;
constructor(private compiler: Compiler) {}
ngOnInit() {
this.createComponentFactory(MyDynamicComponent).then(
(factory: ComponentFactory<MyDynamicComponent>) => this.viewContainer.createComponent(factory),
(err: any) => console.error(err));
}
private createComponentFactory(/*...*/) {/*...*/}
}
<ng-container #placeholder></ng-container>
似乎也可以正常工作(用ng-container
替换ng-template
).我喜欢这种方法,因为<ng-container>
明确针对此用例(不添加标签的容器),并且可以在NgIf
之类的其他情况下使用,而无需包装在真正的标签中.
It seems <ng-container #placeholder></ng-container>
is also working (replace ng-template
by ng-container
). I like this approach because <ng-container>
is clearly addressed to this usecase (a container that don't add a tag) and can be used in other situations like NgIf
without wrapping in a real tag.
PS:@GünterZöchbauer在一条评论中将我引向正确的讨论,然后我终于回答了我自己的问题.
PS: @GünterZöchbauer directed me to the right discussion in a comment, and I finally answered my own question.
编辑[2018-05-30]:已更新为stackblitz链接,以提供最新的有效示例.
这篇关于Angular2:在DOM中将动态组件作为容器的子代插入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!