有没有办法将组件作为Angular 2中DOM标签的子(而不是兄弟)动态插入?
有很多示例可以将动态组件作为给定ViewContainerRef
的标记的兄弟项插入,例如(对于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:
<div></div>
<my-dynamic-component></my-dynamic-component>
预期结果:
<div>
<my-dynamic-component></my-dynamic-component>
</div>
使用SomeComponent
的ViewContainerRef
具有相同的结果,它仍然将生成的组件作为兄弟项插入,而不是子项。我可以接受这样的解决方案:模板为空,并且动态组件被插入到模板中(在组件选择器标记内)。
当使用ng2-dragula这样的库从动态组件和benefit from the model updates列表中拖动时,DOM结构非常重要。额外的div在可拖动元素的列表中,但在模型之外,这打破了拖放逻辑。
有些人说这是不可能的(c.f. this comment),但这听起来像是一个非常令人惊讶的限制。
发布于 2016-06-29 17:23:37
TL;DR:将<div #placeholder></div>
替换为<div><ng-template #placeholder></ng-template></div>
以插入到div
中。
以下是一个working stackblitz example (Angular 6),以及相关代码:
@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
,而不需要包装在真正的标签中。
PS:@GünterZöchbauer在评论中引导我进行了正确的讨论,我最终回答了自己的问题。
编辑2018-05-30:更新到stackblitz链接,以获得有效的、最新的示例。
发布于 2017-07-19 02:33:36
我一直在为同样的问题寻找解决方案,但认可的答案对我来说不起作用。但我已经找到了更好的、更符合逻辑的解决方案,如何将动态创建的组件作为子组件附加到当前的宿主元素。
其思想是使用新创建的组件的元素引用,并通过渲染服务将其附加到当前的元素引用。我们可以通过组件的注入器属性来获取组件对象。
代码如下:
@Directive({
selector: '[mydirective]'
})
export class MyDirectiveDirective {
constructor(
private cfResolver: ComponentFactoryResolver,
public vcRef: ViewContainerRef,
private renderer: Renderer2
) {}
public appendComponent() {
const factory =
this.cfResolver.resolveComponentFactory(MyDynamicComponent);
const componentRef = this.vcRef.createComponent(factory);
this.renderer.appendChild(
this.vcRef.element.nativeElement,
componentRef.injector.get(MyDynamicComponent).elRef.nativeElement
);
}
}
发布于 2018-05-25 10:14:38
我的解决方案非常类似于@Bohdan Khodakivskyi。但我试过Renderer2了。
constructor(
private el: ElementRef,
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver,
private render: Renderer2
) {}
ngOnInit() {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
MyDynamicComponent,
);
const componentRef = this.viewContainerRef.createComponent(componentFactory);
this.render.appendChild(this.el.nativeElement, componentRef.location.nativeElement)
}
https://stackoverflow.com/questions/38093727
复制相似问题