I am trying to extend the functionality of this component by adding a generic event emitter
import {
Component,
Directive,
NgModule,
Input,
ViewContainerRef,
Compiler,
ComponentFactory,
ModuleWithComponentFactories,
ComponentRef,
ReflectiveInjector
} from '@angular/core';
import { RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
export function createComponentFactory(compiler: Compiler, metadata: Component): Promise<ComponentFactory<any>> {
const cmpClass = class DynamicComponent { };
const decoratedCmp = Component(metadata)(cmpClass);
@NgModule({ imports: [CommonModule, RouterModule], declarations: [decoratedCmp] })
class DynamicHtmlModule { }
return compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule)
.then((moduleWithComponentFactory: ModuleWithComponentFactories<any>) => {
return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp);
});
}
@Directive({ selector: 'html-outlet' })
export class HtmlOutlet {
@Input() html: string;
cmpRef: ComponentRef<any>;
constructor(private vcRef: ViewContainerRef, private compiler: Compiler) { }
ngOnChanges() {
const html = this.html;
if (!html) return;
if (this.cmpRef) {
this.cmpRef.destroy();
}
const compMetadata = new Component({
selector: 'dynamic-html',
template: this.html,
});
createComponentFactory(this.compiler, compMetadata)
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []);
});
}
ngOnDestroy() {
if (this.cmpRef) {
this.cmpRef.destroy();
}
}
}
Crediting original author https://gist.github.com/benjamincharity/8116414c7f38cffe3cef0e44fe44295d
example of the desired event
@Output() genericEventEmitter = new EventEmitter<string>();
emitEvent(data:string){
this.genericEventEmitter.emit(data)
}
I've tried adding this to the htmlOutlet class and also the DynamicComponent I'm getting the error message
ERROR TypeError: _co.emitEvent is not a function
at Object.eval [as handleEvent] (DynamicComponent.html:6)
This is telling me that the function is not being properly added to the class when it's being created within the componentFactory
Any Angular Gurus, able to shed some insight on how I can get this to work?
Managed to daisy chain a Subject in the dynamic component to an event emitter in the html outlet which can be captured by the parent of the html outlet
import {
Component,
Directive,
NgModule,
Input,
ViewContainerRef,
Compiler,
ComponentFactory,
ModuleWithComponentFactories,
ComponentRef,
ReflectiveInjector,
EventEmitter,
Output,
} from '@angular/core';
import { Observable, Subject } from 'rxjs'
import { RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import { PartialObject } from 'lodash';
export function createComponentFactory(compiler: Compiler, metadata: Component): Promise<ComponentFactory<any>> {
const cmpClass = class DynamicComponent {
outputter: Subject<Object> = new Subject();
genEmit(data) {
this.outputter.next(data)
}
};
const decoratedCmp = Component(metadata)(cmpClass);
@NgModule({ imports: [CommonModule, RouterModule], declarations: [decoratedCmp] })
class DynamicHtmlModule {
}
return compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule)
.then((moduleWithComponentFactory: ModuleWithComponentFactories<any>) => {
return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp);
});
}
@Directive({ selector: 'html-outlet' })
export class HtmlOutlet {
@Input() html: string;
cmpRef: ComponentRef<any>;
@Output() genericEmitter = new EventEmitter();
constructor(private vcRef: ViewContainerRef, private compiler: Compiler) {
}
ngOnChanges() {
const html = this.html;
if (!html) return;
if (this.cmpRef) {
this.cmpRef.destroy();
}
const compMetadata = new Component({
selector: 'dynamic-html',
template: this.html,
});
createComponentFactory(this.compiler, compMetadata)
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []);
this.cmpRef.instance.outputter.subscribe(v => {
this.genericEmitter.emit(v)
})
});
}
ngOnDestroy() {
if (this.cmpRef) {
this.cmpRef.destroy();
}
}
}