使用 ng-content 动态创建 angular2 组件

Posted

技术标签:

【中文标题】使用 ng-content 动态创建 angular2 组件【英文标题】:Creating an angular2 component with ng-content dynamically 【发布时间】:2018-07-21 04:53:21 【问题描述】:

我想在使用ComponentFactoryResolver 动态实例化组件时设置<ng-content> 的主体。

我发现我可以使用ComponentRef 访问输入和输出,但不能设置<ng-content>

请注意<ng-content>我打算设置可以包含简单的文本/可以跨越动态创建的组件

@Component(
    selector: 'app-component-to-project',
    template: `<ng-content></ng-content>`
)
export class ComponentToProject implements AfterContentInit 

    ngAfterContentInit() 
        // We will do something important with content here
    




@Directive(
    selector: 'appProjectionMarker'
)
export class ProjectionMarkerDirective implements OnInit 

    constructor(private viewContainerRef: ViewContainerRef, private componentFactoryResolver: ComponentFactoryResolver) 
    

    ngOnInit() 
        const componentFactory: ComponentFactory<ComponentToProject> = this.componentFactoryResolver.resolveComponentFactory(ComponentToProject);
        const componentRef: ComponentRef<ComponentToProject> = this.viewContainerRef.createComponent(componentFactory);
        // Question: How to set content before the child's afterContentInit is invoked
    



@Component(
    selector: 'appTestComponent',
    template: `<div appProjectionMarker></div>`
)
export class TestComponent 

【问题讨论】:

使用projectableNodes参数***.com/questions/41372334/… 我可以添加一个动态组件作为projectableNodes,这样子指令的父级可以使用@ContentChild吗? 既然是projectableNodes,我假设我只能通过DOM元素 不,您可以将组件注入其中或模板。但是你应该只操作节点 20.00youtube.com/watch?v=EMjTp12VbQ8 【参考方案1】:

vcRef.createComponent 方法有 projectableNodes 参数

createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>;

您可以使用它来将一个组件动态注入到另一个组件中。

假设我们有以下组件

@Component(
    selector: 'card',
    template: `
        <div class="card__top">
            <h2>Creating a angular2 component with ng-content dynamically</h2>
        </div>
        <div class="card__body">
            <ng-content></ng-content>
        </div>
        <div class="card__bottom">
            <ng-content></ng-content>
        </div>
    `
)
export class CardComponent 

我们希望动态创建它并在其ng-content 位置插入一些控件。可以这样做:

const bodyFactory = this.cfr.resolveComponentFactory(CardBodyComponent);
const footerFactory = this.cfr.resolveComponentFactory(CardFooterComponent);

let bodyRef = this.vcRef.createComponent(bodyFactory);
let footerRef = this.vcRef.createComponent(footerFactory);

const cardFactory = this.cfr.resolveComponentFactory(CardComponent);

const cardRef = this.vcRef.createComponent(
    cardFactory,
    0,
    undefined,
    [
        [bodyRef.location.nativeElement],
        [footerRef.location.nativeElement]
    ]
);

Plunker Example

另见

Why is projectableNodes an any[][]?

Pawel Kozlowski - Reactive parenting with Angular 2 - NG-BE 2016

【讨论】:

在这种情况下你事先知道有两个ng-content,如果对象是动态传递的,你怎么知道有多少呢?我的意思是,如果 CardComponent 可以是任何组件? 我刚刚发现如何使用ComponentFactory.ngContentSelectors 知道投影的数量,所以在本例中为 cardFactory.ngContentSelectors.length

以上是关于使用 ng-content 动态创建 angular2 组件的主要内容,如果未能解决你的问题,请参考以下文章

动态插入 ng-content 选择

如何在 Angular 2 中编译 ng-content 中的动态模板

Angular ng-content 不适用于 mat-form-field

带有 ng-content -> form.valid/dirty 等的 Angular 表单不起作用

使用 ng-content 的角度传递模板参考

使用 ng-content 时在表单验证中不考虑输入