angular - Hvordan bruke Output i dynamisk opprettet komponent
Jeg bruker denne teknikken for dynamisk å lage komponent:
import {
Component, Input, ViewContainerRef, ViewChild, ReflectiveInjector, ComponentFactoryResolver,
Output, EventEmitter
} from '@angular/core';
@Component({
selector: 'dynamic-component',
template: `
<div #dynamicComponentContainer></div>
`,
})
export default class DynamicLayerComponent {
currentComponent = null;
@ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer: ViewContainerRef;
@Output() visibility = new EventEmitter<boolean>();
// component: Class for the component you want to create
// inputs: An object with key/value pairs mapped to input name/input value
@Input() set componentData(data: {component: any, inputs: any }) {
console.log('setting');
if (!data) {
return;
}
// Inputs need to be in the following format to be resolved properly
let inputProviders = Object.keys(data.inputs).map((inputName) => {return {provide: inputName, useValue: data.inputs[inputName]};});
let resolvedInputs = ReflectiveInjector.resolve(inputProviders);
// We create an injector out of the data we want to pass down and this components injector
let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.dynamicComponentContainer.parentInjector);
// We create a factory out of the component we want to create
let factory = this.resolver.resolveComponentFactory(data.component);
// We create the component using the factory and the injector
let component = factory.create(injector);
// We insert the component into the dom container
this.dynamicComponentContainer.insert(component.hostView);
// We can destroy the old component is we like by calling destroy
if (this.currentComponent) {
console.log('fdsafa');
this.currentComponent.destroy();
}
this.currentComponent = component;
}
constructor(private resolver: ComponentFactoryResolver) {
console.log('dfsd');
}
}
Og så bruker jeg det slik:
<div *ngFor="let layer of sortedItems" class="single-layer">
<div>
<dynamic-component #DynamicLayer
[componentData]="{
component: layer.componentClass,
inputs: {
layerItem: layer,
sortFilter: sortFilter
}
}"
(visibility)="setLayerVisibility(layer, $event)">
</dynamic-component>
</div>
Problemet er at jeg ikke klarer å binde til en hendelse, det fungerer ikke når jeg binder til (visibility). setLayerVisibility blir ikke kalt når hendelsen inntreffer. Hvordan kan jeg fikse det problemet?
Selvfølgelig har prøvekomponenten min basert på componentClass @Output satt som:
@Output() visibility = new EventEmitter<boolean>();
private visibilityChanged() {
this.visibility.emit(this.layerItem.visible);
}
Svar #1
Din fabrikk:
factory.create(injector);
vil returnere et ComponentRef-objekt, og med dette objektet kan du få tilgang til komponenten selv.
Du kan abonnere på den hendelsen via:
component.instance.visibility.subscribe(v => ...);
Svar #2
Abonner på utgangshendelsen slik:
@ViewChild('yourComponentRef', { read: ViewContainerRef }) container: ViewContainerRef;
// Reference for dynamic component
private _ref;
constructor(
private _cfr: ComponentFactoryResolver){ }
public addDynamicComponent() {
const comp =
this._cfr.resolveComponentFactory(<YOUR_DYNAMIC_COMPONENT_HERE>);
this._ref = this.container.createComponent(comp);
// Input to dynamic component
this._ref.instance.inputVarHere = [1, 2, 3];
// Handles output event, just emit your output here
this._ref.instance.outputEventHere.subscribe(data => {
console.log(data);
});
}
public removeDynamicComponent() {
this._ref.destroy();
}
I din HTML-fil
<!-- Section to load dynamic component -->
<div #yourComponentRef></div>
