I'm working with dynamic components, I followed this tutorial and works fine.
This is my implementation
dynamic-component.directive.ts
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[DynamicComponent]'
})
export class DynamicComponentDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
And, this is the logic, to create dynamic components. It can detect when data is emitted with @Output
This is the code
import { Component, ComponentFactoryResolver, ComponentRef, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
import { DynamicComponentDirective } from './dynamic-component.directive';
import { DynamicComponentInterface } from '@interfaces/dynamic-component.interface';
@Component({
selector: 'dynamic-component',
template: '<ng-template DynamicComponent></ng-template>'
})
export class DynamicComponent implements OnInit, OnDestroy, OnChanges {
@Input() component!: DynamicComponentInterface;
@Output() sentData: EventEmitter<any> = new EventEmitter<any>();
@ViewChild(DynamicComponentDirective, { static: true })
directive!: DynamicComponentDirective;
componentRef!: ComponentRef<DynamicComponentInterface>;
constructor(
private factoryResolver: ComponentFactoryResolver
) { }
ngOnInit(): void {
if ( this.component ) {
this.loadComponent();
}
}
ngOnDestroy(): void {
this.componentRef.destroy();
}
ngOnChanges( changes: SimpleChanges ): void {
console.log( changes );
}
loadComponent(): void {
const componentFactory = this.factoryResolver
.resolveComponentFactory( this.component.component );
const containerRef = this.directive.viewContainerRef;
this.componentRef = containerRef
.createComponent<DynamicComponentInterface>( componentFactory );
this.componentRef.instance.data = this.component.data;
this.componentRef.instance.emitter?.
subscribe( (values: any) => this.sentData.emit( values ) );
this.componentRef.changeDetectorRef.detectChanges();
}
}
All works fine, This is my how it works...
in the app.component.html
<mat-accordion [multi]="true">
<mat-expansion-panel *ngFor="let expansion of salaryPanelRight" [expanded]="true">
<mat-expansion-panel-header>
{{ expansion.title }}
</mat-expansion-panel-header>
<dynamic-component [component]="expansion.panel"></dynamic-component>
</mat-expansion-panel>
</mat-accordion>
This is how the dynamic-component
builds on the logic file
import { Component } from '@angular/core';
import { DynamicComponentInterface } from '@interfaces/dynamic-component.interface';
import { PanelJobDetailsComponent } from './components/panel-job-details/panel-job-details.component';
import { PanelSalaryDetailsResumeComponent } from './components/panel-salary-details-resume/panel-salary-details-resume.component';
import { PanelSalaryResumeComponent } from './components/panel-salary-resume/panel-salary-resume.component';
@Component({
selector: 'app-salary-data',
templateUrl: './salary-data.component.html',
styleUrls: ['./salary-data.component.scss']
})
export class SalaryDataComponent {
salaryPanelRight: SalaryPanel [] = [
{
title: $localize`:@@salary-tab-panel-resume-details: Title 1`,
panel: {
component: PanelJobDetailsComponent,
data: {
hireSchema: null
}
},
},
{
title: $localize`:@@salary-tab-panel-resume-salary: Title 2`,
panel: {
component: PanelSalaryResumeComponent
}
},
{
title: $localize`:@@salary-tab-panel-resume-salary-details: Title 3`,
panel: {
component: PanelSalaryDetailsResumeComponent
}
},
];
constructor() { }
getValues( input: any ): void {
const value = input.target.value;
this.salaryPanelRight[0].panel.data.hireSchema = value;
}
}
interface SalaryPanel {
title: string;
panel: DynamicComponentInterface;
}
For example PanelJobDetailsComponent
has this @Input() hireSchema!: string;
and his HTML is only {{ hireSchema }}
It is not changing when I change the value from parent component, exactly in this part
getValues( input: any ): void {
const value = input.target.value;
this.salaryPanelRight[0].panel.data.hireSchema = value;
}
I have read and implemented ngOnChanges
but is not working, the data is not changing. Actually I did this.componentRef.changeDetectorRef.detectChanges();
also but it is not working. When I do console.log
on ngOnChanges
nothing is happening, even I fired blur event from the input to fire the new data.
How can I pass the changed data to my implementation?