ng4 componentFactory 将它放在 DOM 目标中

ng4 componentFactory placing it in the DOM target

我想做什么

我正在开发一个投票系统,该系统将在网站的多个组件中重复使用。为了保持干燥,我想从任何组件创建投票组件,进入指定的 DOM 元素。创建组件后,必须设置实例变量(在本例中为 model:stringpk:number,两者都 public).

预期结果

我希望组件在指定位置渲染,打印工厂创建组件后立即设置的正确数据。投票底部的输出应该是Model: project PK: 1

实际情况

ComponentFactory 当前有两个 个由组件工厂创建的投票组件的输出:

  1. 在正确的位置(目标 div),但没有设置实例变量。

  2. 在页面底部,但这是另一个问题,稍后在另一个主题中讨论。

一些代码

@NgModule({
    ..
    declarations: [
        AppComponent,
        ProjectComponent, // parent for voteContainer
        VoteComponent, // Dynamic component
    ],
    entryComponents: [
        VoteComponent,
    ], ..
})

包含 VoteComponent 工厂的父组件

export class ProjectDetailComponent implements AfterViewInit {
    @ViewChild('voteComponentContainer', {read: ViewContainerRef}) voteComponentContainer;

    public ngAfterViewInit() {
        this.factoryVoteComponent();
    }

    private factoryVoteComponent() {
        const voteComponentFactory = this.componentFactoryResolver.resolveComponentFactory(VoteComponent);
        const voteComponentRef = this.viewContainerRef.createComponent(voteComponentFactory);
        voteComponentRef.instance.model = "project";
        voteComponentRef.instance.pk = 1;
        voteComponentRef.changeDetectorRef.detectChanges();
    }
}

动态组件目标:

<vote-component-container></vote-component-container>

基本投票组件

@Component({
    selector: 'vote-component-container',
    templateUrl: 'vote.component.html',
})

export class VoteComponent {
    public model:string;
    public pk:number;
    public constructor(){}
}

我试过的

我已经为此苦苦挣扎了一段时间,所以 有很多尝试让它发挥作用。最后的尝试是 为工厂创建 ViewChild。

除此之外,我一直在研究名称、设置组件模板接收器的不同方法等。

我想问的

有没有人对我现在尝试的情况有使用动态组件的经验?我希望朝着正确的方向推动如何解决组件在正确位置呈现但没有可用属性的问题。

经过更多研究、测试失败并尝试更多 - 我找到了解决方案。我还不是 100% 满意,因为它变得不那么枯燥和有条理了 - 但现在:

首先,我必须调整将数据传递给动态生成的组件的方式。我必须更新我的选择器目标以接受所需的属性。在我的例子中 modelobjectId.

<vote-component-container [model]="'project'" [objectId]="projectId"></vote-component-container>

到 link 到 VoteComponent 的数据,VoteComponent 本身需要 @Input 这些数据输入的设置器,例如:

import { Input, Component, AfterViewInit } from '@angular/core';

@Component({
    selector: 'vote-component-container',
    templateUrl: 'vote.component.html',
})

export class VoteComponent implements AfterViewInit {
    // Temp public for testing
    public _objectId:number;
    public _model:string;

    public constructor(){}
    public ngAfterViewInit(){
        this.getVotes();
    }

    @Input('objectId')
    set objectId(objectId:number){
        this._objectId = objectId;
    }

    @Input('model')
    set model(model:string){
        this._model = model;
    }

    public getVotes(){
        ...
    }
}

最终在我的父组件中,我预计 params['id'] 部分是在 ngAfterInit 中调用该函数时出现的。但是没有,所以我只好等待承诺..

@ViewChild('voteComponentContainer', {read: ViewContainerRef}) target: ViewContainerRef;
private factoryVoteComponent(){
    this.activatedRoute.params.subscribe((params: Params) => {
        this.model = 'project';
        this.projectId = params['id'];

        let voteComponentFactory = this.componentFactoryResolver.resolveComponentFactory(VoteComponent);
        this.voteComponentRef = this.viewContainerRef.createComponent(voteComponentFactory);
        this.voteComponentRef.changeDetectorRef.detectChanges();
    });
}