Ng4 componentFactory by putting it on the DOM target

What am i trying to do

I am working on a voting system that will be reused in many components around the website. To keep it dry, I want to create a voting component from any component in the assigned DOM element. After the component has been created, instance variables must be set (in this case model:string and pk:number , as public).

Expected Result

I expect that the component will be displayed in the specified location by printing the necessary data that was installed immediately after the factory created the component. The output at the bottom of the votes should be Model: project PK: 1

Actual situation

Currently, ComponentFactory has two outputs of the voting component created by the Component factory:

  • In the right place (target div), but without the given instance variables. image1

  • At the bottom of the page, but this is another problem, for a later time and in a different section.

Some code

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

containing component VoteComponent factory

 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(); } } 

The purpose of the dynamic component:

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

The main component of voting

 @Component({ selector: 'vote-component-container', templateUrl: 'vote.component.html', }) export class VoteComponent { public model:string; public pk:number; public constructor(){} } 

What i tried

I struggled with this for quite some time, so these are quite some attempts to make it work. The last attempt was with the creation of ViewChild for the factory.

In addition, I played with names, different ways of setting the receiver of a component template, etc.

What i want to ask

Does anyone have any experience using dynamic components, as for the situation I'm trying to do now? I was hoping for a push in the right direction, how to fix a problem with a component displayed in the right place, but without the attributes available.

+5
source share
1 answer

After some research, testing, and failure, I found a solution. I'm not 100% satisfied yet, as it becomes a little less dry and organized - but for now:

First, I had to set up a way to transfer my data to a dynamically generated component. I needed to update the target selector system to accept the necessary attributes. In my case, model and objectId .

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

To associate this data with VoteComponent , VoteComponent itself needs @Input installers for these data inputs, for example:

 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(){ ... } } 

and finally, in my parent component, I was expecting the params ['id'] section to be when the function was called in ngAfterInit. But this did not happen, so I had to wait for the promise.

 @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(); }); } 
0
source

Source: https://habr.com/ru/post/1271366/


All Articles