首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Angular2:将动态组件作为容器的子级插入到DOM中

Angular2:将动态组件作为容器的子级插入到DOM中
EN

Stack Overflow用户
提问于 2016-06-29 16:03:30
回答 6查看 45.8K关注 0票数 37

有没有办法将组件作为Angular 2中DOM标签的(而不是兄弟)动态插入?

有很多示例可以将动态组件作为给定ViewContainerRef的标记的兄弟项插入,例如(对于RC3):

代码语言:javascript
复制
@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:

代码语言:javascript
复制
<div></div>
<my-dynamic-component></my-dynamic-component>

预期结果:

代码语言:javascript
复制
<div>
    <my-dynamic-component></my-dynamic-component>
</div>

使用SomeComponentViewContainerRef具有相同的结果,它仍然将生成的组件作为兄弟项插入,而不是子项。我可以接受这样的解决方案:模板为空,并且动态组件被插入到模板中(在组件选择器标记内)。

当使用ng2-dragula这样的库从动态组件和benefit from the model updates列表中拖动时,DOM结构非常重要。额外的div在可拖动元素的列表中,但在模型之外,这打破了拖放逻辑。

有些人说这是不可能的(c.f. this comment),但这听起来像是一个非常令人惊讶的限制。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2016-06-29 17:23:37

TL;DR:将<div #placeholder></div>替换为<div><ng-template #placeholder></ng-template></div>以插入到div中。

以下是一个working stackblitz example (Angular 6),以及相关代码:

代码语言:javascript
复制
@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链接,以获得有效的、最新的示例。

票数 55
EN

Stack Overflow用户

发布于 2017-07-19 02:33:36

我一直在为同样的问题寻找解决方案,但认可的答案对我来说不起作用。但我已经找到了更好的、更符合逻辑的解决方案,如何将动态创建的组件作为子组件附加到当前的宿主元素。

其思想是使用新创建的组件的元素引用,并通过渲染服务将其附加到当前的元素引用。我们可以通过组件的注入器属性来获取组件对象。

代码如下:

代码语言:javascript
复制
@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
        );
    }
}
票数 12
EN

Stack Overflow用户

发布于 2018-05-25 10:14:38

我的解决方案非常类似于@Bohdan Khodakivskyi。但我试过Renderer2了。

代码语言:javascript
复制
  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)
  }
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38093727

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档