import * as i0 from '@angular/core'; import { InjectionToken, Injectable, Injector, Inject, Optional, Directive, Input, Host, NgModule, EventEmitter, Component, Output, ElementRef } from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import * as i1 from '@angular/common'; /** * @public */ function defaultEventArgumentFactory() { return '$event'; } /** * @public */ const IoEventArgumentToken = new InjectionToken('EventArgument', { providedIn: 'root', factory: defaultEventArgumentFactory, }); /** * @public * @deprecated Since v10.4.0 - Use {@link IoEventArgumentToken} instead! */ const EventArgumentToken = IoEventArgumentToken; /** * A token that holds custom context of the output handlers * * @public */ const IoEventContextToken = new InjectionToken('IoEventContext'); /** * A token that holds provider for custom context of the output handlers * which should be provided using {@link IoEventContextToken} token * * @public */ const IoEventContextProviderToken = new InjectionToken('IoEventContextProvider'); /** * @public */ const DynamicComponentInjectorToken = new InjectionToken('DynamicComponentInjector'); /** * @public */ class IoServiceOptions { constructor() { this.trackOutputChanges = false; } } /** @nocollapse */ IoServiceOptions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: IoServiceOptions, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); /** @nocollapse */ IoServiceOptions.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: IoServiceOptions, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: IoServiceOptions, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); /** * @public */ class IoService { constructor(injector, differs, // TODO: Replace ComponentFactoryResolver once new API is created // @see https://github.com/angular/angular/issues/44926 // eslint-disable-next-line deprecation/deprecation cfr, options, compInjector, eventArgument, cdr, eventContextProvider) { this.injector = injector; this.differs = differs; this.cfr = cfr; this.options = options; this.compInjector = compInjector; this.eventArgument = eventArgument; this.cdr = cdr; this.eventContextProvider = eventContextProvider; this.lastComponentInst = null; this.lastChangedInputs = new Set(); this.inputsDiffer = this.differs.find({}).create(); // TODO: Replace ComponentFactory once new API is created // @see https://github.com/angular/angular/issues/44926 // eslint-disable-next-line deprecation/deprecation this.compFactory = null; this.outputsShouldDisconnect$ = new Subject(); this.inputs = {}; this.outputs = {}; this.outputsChanged = () => false; if (this.options.trackOutputChanges) { const outputsDiffer = this.differs.find({}).create(); this.outputsChanged = (outputs) => !!outputsDiffer.diff(outputs); } } get compRef() { return this.compInjector.componentRef; } get componentInst() { return this.compRef ? this.compRef.instance : null; } get componentInstChanged() { if (this.lastComponentInst !== this.componentInst) { this.lastComponentInst = this.componentInst; return true; } else { return false; } } ngOnDestroy() { this.disconnectOutputs(); } /** * Call update whenever inputs/outputs may or did change. * * It will detect both new and mutated changes. */ update(inputs, outputs) { if (!this.compRef) { this.disconnectOutputs(); return; } const changes = this.updateIO(inputs, outputs); const compChanged = this.componentInstChanged; const inputsChanges = this.getInputsChanges(compChanged); const outputsChanged = this.outputsChanged(this.outputs); if (inputsChanges) { this.updateChangedInputs(inputsChanges); } if (compChanged || inputsChanges) { this.updateInputs(compChanged || !this.lastChangedInputs.size); } if (compChanged || outputsChanged || changes.outputsChanged) { this.bindOutputs(); } } updateIO(inputs, outputs) { if (!inputs) { inputs = {}; } if (!outputs) { outputs = {}; } const inputsChanged = this.inputs !== inputs; const outputsChanged = this.outputs !== outputs; this.inputs = inputs; this.outputs = outputs; return { inputsChanged, outputsChanged }; } updateInputs(isFirstChange = false) { if (isFirstChange) { this.updateCompFactory(); } const compRef = this.compRef; const inputs = this.inputs; if (!inputs || !compRef) { return; } const ifInputChanged = this.lastChangedInputs.size ? (name) => this.lastChangedInputs.has(name) : () => true; Object.keys(inputs) .filter(ifInputChanged) .forEach((name) => compRef.setInput(name, inputs[name])); } bindOutputs() { this.disconnectOutputs(); const compInst = this.componentInst; let outputs = this.outputs; if (!outputs || !compInst) { return; } outputs = this.resolveOutputs(outputs); Object.keys(outputs) .filter((p) => compInst[p]) .forEach((p) => compInst[p] .pipe(takeUntil(this.outputsShouldDisconnect$)) .subscribe((event) => { this.cdr.markForCheck(); return outputs[p](event); })); } disconnectOutputs() { this.outputsShouldDisconnect$.next(); } getInputsChanges(isCompChanged) { if (isCompChanged) { this.inputsDiffer.diff({}); } return this.inputsDiffer.diff(this.inputs); } updateChangedInputs(differ) { this.lastChangedInputs.clear(); const addRecordKeyToSet = (record) => this.lastChangedInputs.add(record.key); differ.forEachAddedItem(addRecordKeyToSet); differ.forEachChangedItem(addRecordKeyToSet); differ.forEachRemovedItem(addRecordKeyToSet); } // TODO: Replace ComponentFactory once new API is created // @see https://github.com/angular/angular/issues/44926 // eslint-disable-next-line deprecation/deprecation resolveCompFactory() { if (!this.compRef) { return null; } try { try { return this.cfr.resolveComponentFactory(this.compRef.componentType); } catch (e) { // Fallback if componentType does not exist (happens on NgComponentOutlet) return this.cfr.resolveComponentFactory(this.compRef.instance.constructor); } } catch (e) { // Factory not available - bailout return null; } } updateCompFactory() { this.compFactory = this.resolveCompFactory(); } resolveOutputs(outputs) { this.updateOutputsEventContext(); outputs = this.processOutputs(outputs); if (!this.compFactory) { return outputs; } return this.remapIO(outputs, this.compFactory.outputs); } updateOutputsEventContext() { if (this.eventContextProvider) { // Resolve custom context from local provider const eventContextInjector = Injector.create({ name: 'EventContext', parent: this.injector, providers: [this.eventContextProvider], }); this.outputsEventContext = eventContextInjector.get(IoEventContextToken); } else { // Try to get global context this.outputsEventContext = this.injector.get(IoEventContextToken, null); } } processOutputs(outputs) { const processedOutputs = {}; Object.keys(outputs).forEach((key) => { const outputExpr = outputs[key]; let outputHandler; if (typeof outputExpr === 'function') { outputHandler = outputExpr; } else { outputHandler = outputExpr && this.processOutputArgs(outputExpr); } if (this.outputsEventContext && outputHandler) { outputHandler = outputHandler.bind(this.outputsEventContext); } processedOutputs[key] = outputHandler; }); return processedOutputs; } processOutputArgs(output) { const eventArgument = this.eventArgument; const args = 'args' in output ? output.args || [] : [eventArgument]; const eventIdx = args.indexOf(eventArgument); const handler = output.handler; // When there is no event argument - use just arguments if (eventIdx === -1) { return function () { return handler.apply(this, args); }; } return function (event) { const argsWithEvent = [...args]; argsWithEvent[eventIdx] = event; return handler.apply(this, argsWithEvent); }; } remapIO(io, mapping) { const newIO = {}; Object.keys(io).forEach((key) => { const newKey = this.findPropByTplInMapping(key, mapping) || key; newIO[newKey] = io[key]; }); return newIO; } findPropByTplInMapping(tplName, mapping) { for (const map of mapping) { if (map.templateName === tplName) { return map.propName; } } return null; } } /** @nocollapse */ IoService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: IoService, deps: [{ token: i0.Injector }, { token: i0.KeyValueDiffers }, { token: i0.ComponentFactoryResolver }, { token: IoServiceOptions }, { token: DynamicComponentInjectorToken }, { token: IoEventArgumentToken }, { token: i0.ChangeDetectorRef }, { token: IoEventContextProviderToken, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); /** @nocollapse */ IoService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: IoService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: IoService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.KeyValueDiffers }, { type: i0.ComponentFactoryResolver }, { type: IoServiceOptions }, { type: undefined, decorators: [{ type: Inject, args: [DynamicComponentInjectorToken] }] }, { type: undefined, decorators: [{ type: Inject, args: [IoEventArgumentToken] }] }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{ type: Inject, args: [IoEventContextProviderToken] }, { type: Optional }] }]; } }); /** * @public */ class IoFactoryService { constructor(injector) { this.injector = injector; } create(componentInjector, ioOptions) { const providers = [ { provide: IoService, useClass: IoService }, { provide: DynamicComponentInjectorToken, useValue: componentInjector }, ]; if (ioOptions) { providers.push({ provide: IoServiceOptions, useValue: ioOptions }); } const ioInjector = Injector.create({ name: 'IoInjector', parent: ioOptions?.injector ?? this.injector, providers, }); return ioInjector.get(IoService); } } /** @nocollapse */ IoFactoryService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: IoFactoryService, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); /** @nocollapse */ IoFactoryService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: IoFactoryService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: IoFactoryService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: i0.Injector }]; } }); /** * @public */ class ComponentOutletIoDirective { constructor(ioService) { this.ioService = ioService; } ngDoCheck() { this.ioService.update(this.ngComponentOutletNdcDynamicInputs, this.ngComponentOutletNdcDynamicOutputs); } } /** @nocollapse */ ComponentOutletIoDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: ComponentOutletIoDirective, deps: [{ token: IoService }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ ComponentOutletIoDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.1.3", type: ComponentOutletIoDirective, isStandalone: true, selector: "[ngComponentOutletNdcDynamicInputs],[ngComponentOutletNdcDynamicOutputs]", inputs: { ngComponentOutletNdcDynamicInputs: "ngComponentOutletNdcDynamicInputs", ngComponentOutletNdcDynamicOutputs: "ngComponentOutletNdcDynamicOutputs" }, providers: [IoService], exportAs: ["ndcDynamicIo"], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: ComponentOutletIoDirective, decorators: [{ type: Directive, args: [{ selector: // eslint-disable-next-line @angular-eslint/directive-selector '[ngComponentOutletNdcDynamicInputs],[ngComponentOutletNdcDynamicOutputs]', exportAs: 'ndcDynamicIo', standalone: true, providers: [IoService], }] }], ctorParameters: function () { return [{ type: IoService }]; }, propDecorators: { ngComponentOutletNdcDynamicInputs: [{ type: Input }], ngComponentOutletNdcDynamicOutputs: [{ type: Input }] } }); /** * @public */ class ComponentOutletInjectorDirective { constructor(componentOutlet) { this.componentOutlet = componentOutlet; } get componentRef() { // NOTE: Accessing private APIs of Angular return this.componentOutlet._componentRef; } } /** @nocollapse */ ComponentOutletInjectorDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: ComponentOutletInjectorDirective, deps: [{ token: i1.NgComponentOutlet, host: true }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ ComponentOutletInjectorDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.1.3", type: ComponentOutletInjectorDirective, isStandalone: true, selector: "[ngComponentOutlet]", providers: [ { provide: DynamicComponentInjectorToken, useExisting: ComponentOutletInjectorDirective, }, ], exportAs: ["ndcComponentOutletInjector"], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: ComponentOutletInjectorDirective, decorators: [{ type: Directive, args: [{ // eslint-disable-next-line @angular-eslint/directive-selector selector: '[ngComponentOutlet]', exportAs: 'ndcComponentOutletInjector', standalone: true, providers: [ { provide: DynamicComponentInjectorToken, useExisting: ComponentOutletInjectorDirective, }, ], }] }], ctorParameters: function () { return [{ type: i1.NgComponentOutlet, decorators: [{ type: Host }] }]; } }); /** * @public */ class ComponentOutletInjectorModule { } /** @nocollapse */ ComponentOutletInjectorModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: ComponentOutletInjectorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); /** @nocollapse */ ComponentOutletInjectorModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.1.3", ngImport: i0, type: ComponentOutletInjectorModule, imports: [ComponentOutletInjectorDirective, ComponentOutletIoDirective], exports: [ComponentOutletInjectorDirective, ComponentOutletIoDirective] }); /** @nocollapse */ ComponentOutletInjectorModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: ComponentOutletInjectorModule }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: ComponentOutletInjectorModule, decorators: [{ type: NgModule, args: [{ imports: [ComponentOutletInjectorDirective, ComponentOutletIoDirective], exports: [ComponentOutletInjectorDirective, ComponentOutletIoDirective], }] }] }); /** * @public */ class DynamicIoDirective { constructor(ioService) { this.ioService = ioService; } ngDoCheck() { this.ioService.update(this.ndcDynamicInputs, this.ndcDynamicOutputs); } } /** @nocollapse */ DynamicIoDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicIoDirective, deps: [{ token: IoService }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ DynamicIoDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.1.3", type: DynamicIoDirective, isStandalone: true, selector: "[ndcDynamicInputs],[ndcDynamicOutputs]", inputs: { ndcDynamicInputs: "ndcDynamicInputs", ndcDynamicOutputs: "ndcDynamicOutputs" }, providers: [IoService], exportAs: ["ndcDynamicIo"], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicIoDirective, decorators: [{ type: Directive, args: [{ selector: '[ndcDynamicInputs],[ndcDynamicOutputs]', exportAs: 'ndcDynamicIo', standalone: true, providers: [IoService], }] }], ctorParameters: function () { return [{ type: IoService }]; }, propDecorators: { ndcDynamicInputs: [{ type: Input }], ndcDynamicOutputs: [{ type: Input }] } }); /** * @public */ class DynamicIoModule { } /** @nocollapse */ DynamicIoModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicIoModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); /** @nocollapse */ DynamicIoModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.1.3", ngImport: i0, type: DynamicIoModule, imports: [DynamicIoDirective], exports: [DynamicIoDirective, ComponentOutletInjectorModule] }); /** @nocollapse */ DynamicIoModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicIoModule, imports: [ComponentOutletInjectorModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicIoModule, decorators: [{ type: NgModule, args: [{ imports: [DynamicIoDirective], exports: [DynamicIoDirective, ComponentOutletInjectorModule], }] }] }); /** * @public */ class DynamicComponent { constructor(vcr) { this.vcr = vcr; this.ndcDynamicCreated = new EventEmitter(); this.componentRef = null; } ngOnChanges(changes) { if (DynamicComponent.UpdateOnInputs.some((input) => changes.hasOwnProperty(input))) { this.createDynamicComponent(); } } createDynamicComponent() { this.vcr.clear(); this.componentRef = null; if (this.ndcDynamicComponent) { this.componentRef = this.vcr.createComponent(this.ndcDynamicComponent, { index: 0, injector: this._resolveInjector(), projectableNodes: this.ndcDynamicContent, ngModuleRef: this.ndcDynamicNgModuleRef, environmentInjector: this.ndcDynamicEnvironmentInjector, }); this.ndcDynamicCreated.emit(this.componentRef); } } _resolveInjector() { let injector = this.ndcDynamicInjector || this.vcr.injector; if (this.ndcDynamicProviders) { injector = Injector.create({ providers: this.ndcDynamicProviders, parent: injector, }); } return injector; } } DynamicComponent.UpdateOnInputs = [ 'ndcDynamicComponent', 'ndcDynamicInjector', 'ndcDynamicProviders', 'ndcDynamicContent', 'ndcDynamicNgModuleRef', 'ndcDynamicEnvironmentInjector', ]; /** @nocollapse */ DynamicComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicComponent, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component }); /** @nocollapse */ DynamicComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.3", type: DynamicComponent, isStandalone: true, selector: "ndc-dynamic", inputs: { ndcDynamicComponent: "ndcDynamicComponent", ndcDynamicInjector: "ndcDynamicInjector", ndcDynamicProviders: "ndcDynamicProviders", ndcDynamicContent: "ndcDynamicContent", ndcDynamicNgModuleRef: "ndcDynamicNgModuleRef", ndcDynamicEnvironmentInjector: "ndcDynamicEnvironmentInjector" }, outputs: { ndcDynamicCreated: "ndcDynamicCreated" }, providers: [ { provide: DynamicComponentInjectorToken, useExisting: DynamicComponent }, ], usesOnChanges: true, ngImport: i0, template: '', isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicComponent, decorators: [{ type: Component, args: [{ selector: 'ndc-dynamic', standalone: true, template: '', providers: [ { provide: DynamicComponentInjectorToken, useExisting: DynamicComponent }, ], }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }]; }, propDecorators: { ndcDynamicComponent: [{ type: Input }], ndcDynamicInjector: [{ type: Input }], ndcDynamicProviders: [{ type: Input }], ndcDynamicContent: [{ type: Input }], ndcDynamicNgModuleRef: [{ type: Input }], ndcDynamicEnvironmentInjector: [{ type: Input }], ndcDynamicCreated: [{ type: Output }] } }); /** * @public */ class DynamicModule { } /** @nocollapse */ DynamicModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); /** @nocollapse */ DynamicModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.1.3", ngImport: i0, type: DynamicModule, imports: [DynamicIoModule, DynamicComponent], exports: [DynamicIoModule, DynamicComponent] }); /** @nocollapse */ DynamicModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicModule, imports: [DynamicIoModule, DynamicComponent, DynamicIoModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicModule, decorators: [{ type: NgModule, args: [{ imports: [DynamicIoModule, DynamicComponent], exports: [DynamicIoModule, DynamicComponent], }] }] }); /** * @public */ class DynamicAttributesDirective { constructor(renderer, differs, componentInjector) { this.renderer = renderer; this.differs = differs; this.componentInjector = componentInjector; this.attrsDiffer = this.differs.find({}).create(); } get _attributes() { return (this.ndcDynamicAttributes || this.ngComponentOutletNdcDynamicAttributes || {}); } get nativeElement() { return this.componentInjector?.componentRef?.location.nativeElement; } get compType() { return this.componentInjector?.componentRef?.componentType; } get isCompChanged() { if (this.lastCompType !== this.compType) { this.lastCompType = this.compType; return true; } return false; } ngDoCheck() { const isCompChanged = this.isCompChanged; const changes = this.attrsDiffer.diff(this._attributes); if (changes) { this.lastAttrActions = this.changesToAttrActions(changes); } if (changes || (isCompChanged && this.lastAttrActions)) { this.updateAttributes(this.lastAttrActions); } } setAttribute(name, value, namespace) { if (this.nativeElement) { this.renderer.setAttribute(this.nativeElement, name, value, namespace); } } removeAttribute(name, namespace) { if (this.nativeElement) { this.renderer.removeAttribute(this.nativeElement, name, namespace); } } updateAttributes(actions) { if (!this.compType || !actions) { return; } Object.keys(actions.set).forEach((key) => this.setAttribute(key, actions.set[key])); actions.remove.forEach((key) => this.removeAttribute(key)); } changesToAttrActions(changes) { const attrActions = { set: {}, remove: [], }; changes.forEachAddedItem((r) => (attrActions.set[r.key] = r.currentValue)); changes.forEachChangedItem((r) => (attrActions.set[r.key] = r.currentValue)); changes.forEachRemovedItem((r) => attrActions.remove.push(r.key)); return attrActions; } } /** @nocollapse */ DynamicAttributesDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicAttributesDirective, deps: [{ token: i0.Renderer2 }, { token: i0.KeyValueDiffers }, { token: DynamicComponentInjectorToken, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ DynamicAttributesDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.1.3", type: DynamicAttributesDirective, isStandalone: true, selector: "[ndcDynamicAttributes],[ngComponentOutletNdcDynamicAttributes]", inputs: { ndcDynamicAttributes: "ndcDynamicAttributes", ngComponentOutletNdcDynamicAttributes: "ngComponentOutletNdcDynamicAttributes" }, exportAs: ["ndcDynamicAttributes"], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicAttributesDirective, decorators: [{ type: Directive, args: [{ selector: '[ndcDynamicAttributes],[ngComponentOutletNdcDynamicAttributes]', exportAs: 'ndcDynamicAttributes', standalone: true, }] }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.KeyValueDiffers }, { type: undefined, decorators: [{ type: Inject, args: [DynamicComponentInjectorToken] }, { type: Optional }] }]; }, propDecorators: { ndcDynamicAttributes: [{ type: Input }], ngComponentOutletNdcDynamicAttributes: [{ type: Input }] } }); /** * @public */ class DynamicAttributesModule { } /** @nocollapse */ DynamicAttributesModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicAttributesModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); /** @nocollapse */ DynamicAttributesModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.1.3", ngImport: i0, type: DynamicAttributesModule, imports: [DynamicAttributesDirective], exports: [DynamicAttributesDirective, ComponentOutletInjectorModule] }); /** @nocollapse */ DynamicAttributesModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicAttributesModule, imports: [ComponentOutletInjectorModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicAttributesModule, decorators: [{ type: NgModule, args: [{ imports: [DynamicAttributesDirective], exports: [DynamicAttributesDirective, ComponentOutletInjectorModule], }] }] }); /** * Extract type arguments from Angular Directive/Component * * @internal */ function extractNgParamTypes(type) { // NOTE: Accessing private APIs of Angular return type?.ctorParameters?.()?.map((param) => param.type); } /** * @internal */ function isOnDestroy(obj) { return !!obj && typeof obj.ngOnDestroy === 'function'; } /** * @public */ const ReflectRef = new InjectionToken('ReflectRef', { providedIn: 'root', factory: () => window.Reflect, }); /** * @public */ class ReflectService { constructor(reflect) { this.reflect = reflect; } getCtorParamTypes(ctor) { return this.reflect.getMetadata('design:paramtypes', ctor); } } /** @nocollapse */ ReflectService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: ReflectService, deps: [{ token: ReflectRef }], target: i0.ɵɵFactoryTarget.Injectable }); /** @nocollapse */ ReflectService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: ReflectService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: ReflectService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [ReflectRef] }] }]; } }); /** * @public */ function dynamicDirectiveDef(type, inputs, outputs) { return { type, inputs, outputs }; } /** * @public * @experimental Dynamic directives is an experimental API that may not work as expected. * * NOTE: There is a known issue with OnChanges hook not beign triggered on dynamic directives * since this part of functionality has been removed from the core as Angular now * supports this out of the box for dynamic components. */ class DynamicDirectivesDirective { constructor(injector, iterableDiffers, ioFactoryService, reflectService, componentInjector) { this.injector = injector; this.iterableDiffers = iterableDiffers; this.ioFactoryService = ioFactoryService; this.reflectService = reflectService; this.componentInjector = componentInjector; this.ndcDynamicDirectivesCreated = new EventEmitter(); this.dirRef = new Map(); this.dirIo = new Map(); this.dirsDiffer = this.iterableDiffers .find([]) .create((_, def) => def.type); } get directives() { return (this.ndcDynamicDirectives || this.ngComponentOutletNdcDynamicDirectives); } get componentRef() { return this.componentInjector?.componentRef; } get compInstance() { return this.componentRef && this.componentRef.instance; } get isCompChanged() { if (this.lastCompInstance !== this.compInstance) { this.lastCompInstance = this.compInstance; return true; } return false; } get hostInjector() { return this.componentRef?.injector; } ngDoCheck() { if (this.maybeDestroyDirectives()) { return; } const dirsChanges = this.dirsDiffer.diff(this.directives); if (!dirsChanges) { return this.updateDirectives(); } this.processDirChanges(dirsChanges); } ngOnDestroy() { this.destroyAllDirectives(); } maybeDestroyDirectives() { if (this.isCompChanged || !this.componentRef) { this.dirsDiffer.diff([]); this.destroyAllDirectives(); } return !this.componentRef; } processDirChanges(changes) { changes.forEachRemovedItem(({ item }) => this.destroyDirective(item)); const createdDirs = []; changes.forEachAddedItem(({ item }) => { const dirRef = this.initDirective(item); if (dirRef) { createdDirs.push(dirRef); } }); if (createdDirs.length) { this.ndcDynamicDirectivesCreated.emit(createdDirs); } } updateDirectives() { this.directives?.forEach((dir) => this.updateDirective(dir)); } updateDirective(dirDef) { const io = this.dirIo.get(dirDef.type); io?.update(dirDef.inputs, dirDef.outputs); } initDirective(dirDef) { if (this.dirRef.has(dirDef.type)) { return; } const instance = this.createDirective(dirDef.type); const directiveRef = { instance, type: dirDef.type, injector: this.hostInjector, hostComponent: this.componentRef.instance, hostView: this.componentRef.hostView, location: this.componentRef.location, changeDetectorRef: this.componentRef.changeDetectorRef, onDestroy: this.componentRef.onDestroy, }; this.initDirIO(directiveRef, dirDef); this.callInitHooks(instance); this.dirRef.set(directiveRef.type, directiveRef); return directiveRef; } destroyAllDirectives() { this.dirRef.forEach((dir) => this.destroyDirRef(dir)); this.dirRef.clear(); this.dirIo.clear(); } destroyDirective(dirDef) { const dirRef = this.dirRef.get(dirDef.type); if (dirRef) { this.destroyDirRef(dirRef); } this.dirRef.delete(dirDef.type); this.dirIo.delete(dirDef.type); } initDirIO(dirRef, dirDef) { const io = this.ioFactoryService.create({ componentRef: this.dirToCompDef(dirRef) }, { trackOutputChanges: true, injector: this.injector }); io.update(dirDef.inputs, dirDef.outputs); this.dirIo.set(dirRef.type, io); } dirToCompDef(dirRef) { return { changeDetectorRef: this.componentRef.changeDetectorRef, hostView: this.componentRef.hostView, location: this.componentRef.location, destroy: this.componentRef.destroy, onDestroy: this.componentRef.onDestroy, injector: this.componentRef.injector, instance: dirRef.instance, componentType: dirRef.type, setInput: (name, value) => (dirRef.instance[name] = value), }; } destroyDirRef(dirRef) { this.dirIo.get(dirRef.type)?.ngOnDestroy(); if (isOnDestroy(dirRef.instance)) { dirRef.instance.ngOnDestroy(); } } createDirective(dirType) { const directiveInjector = Injector.create({ providers: [ { provide: dirType, useClass: dirType, deps: this.resolveDirParamTypes(dirType), }, { provide: ElementRef, useValue: this.componentRef.location }, ], parent: this.hostInjector, name: `DynamicDirectiveInjector:${dirType.name}@${this.componentRef.componentType.name}`, }); return directiveInjector.get(dirType); } resolveDirParamTypes(dirType) { return ( // First try Angular Compiler's metadata extractNgParamTypes(dirType) ?? // Then fallback to Reflect API this.reflectService.getCtorParamTypes(dirType) ?? // Bailout []); } callInitHooks(obj) { this.callHook(obj, 'ngOnInit'); this.callHook(obj, 'ngDoCheck'); this.callHook(obj, 'ngAfterContentInit'); this.callHook(obj, 'ngAfterContentChecked'); this.callHook(obj, 'ngAfterViewInit'); this.callHook(obj, 'ngAfterViewChecked'); } callHook(obj, hook, args = []) { if (obj[hook]) { obj[hook](...args); } } } /** @nocollapse */ DynamicDirectivesDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicDirectivesDirective, deps: [{ token: i0.Injector }, { token: i0.IterableDiffers }, { token: IoFactoryService }, { token: ReflectService }, { token: DynamicComponentInjectorToken, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ DynamicDirectivesDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.1.3", type: DynamicDirectivesDirective, isStandalone: true, selector: "[ndcDynamicDirectives],[ngComponentOutletNdcDynamicDirectives]", inputs: { ndcDynamicDirectives: "ndcDynamicDirectives", ngComponentOutletNdcDynamicDirectives: "ngComponentOutletNdcDynamicDirectives" }, outputs: { ndcDynamicDirectivesCreated: "ndcDynamicDirectivesCreated" }, providers: [IoFactoryService], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicDirectivesDirective, decorators: [{ type: Directive, args: [{ selector: '[ndcDynamicDirectives],[ngComponentOutletNdcDynamicDirectives]', standalone: true, providers: [IoFactoryService], }] }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.IterableDiffers }, { type: IoFactoryService }, { type: ReflectService }, { type: undefined, decorators: [{ type: Inject, args: [DynamicComponentInjectorToken] }, { type: Optional }] }]; }, propDecorators: { ndcDynamicDirectives: [{ type: Input }], ngComponentOutletNdcDynamicDirectives: [{ type: Input }], ndcDynamicDirectivesCreated: [{ type: Output }] } }); /** * @public */ class DynamicDirectivesModule { } /** @nocollapse */ DynamicDirectivesModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicDirectivesModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); /** @nocollapse */ DynamicDirectivesModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.1.3", ngImport: i0, type: DynamicDirectivesModule, imports: [DynamicDirectivesDirective], exports: [DynamicDirectivesDirective, ComponentOutletInjectorModule] }); /** @nocollapse */ DynamicDirectivesModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicDirectivesModule, imports: [ComponentOutletInjectorModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DynamicDirectivesModule, decorators: [{ type: NgModule, args: [{ imports: [DynamicDirectivesDirective], exports: [DynamicDirectivesDirective, ComponentOutletInjectorModule], }] }] }); /* * Public API Surface of ng-dynamic-component */ /** * Generated bundle index. Do not edit. */ export { ComponentOutletInjectorDirective, ComponentOutletInjectorModule, ComponentOutletIoDirective, DynamicAttributesDirective, DynamicAttributesModule, DynamicComponent, DynamicComponentInjectorToken, DynamicDirectivesDirective, DynamicDirectivesModule, DynamicIoDirective, DynamicIoModule, DynamicModule, EventArgumentToken, IoEventArgumentToken, IoEventContextProviderToken, IoEventContextToken, IoFactoryService, IoService, IoServiceOptions, ReflectRef, ReflectService, defaultEventArgumentFactory, dynamicDirectiveDef }; //# sourceMappingURL=ng-dynamic-component.mjs.map