Dynamic components with full life-cycle support for inputs and outputs
npx @tessl/cli install tessl/npm-ng-dynamic-component@10.8.0ng-dynamic-component is a comprehensive Angular TypeScript library that provides utilities for dynamically creating and managing Angular components, directives, and their inputs/outputs at runtime. It enables developers to create flexible, data-driven user interfaces by allowing components to be selected and rendered programmatically while maintaining Angular's standard component lifecycle hooks, change detection, and event handling.
npm install ng-dynamic-componentimport { DynamicComponent, DynamicModule } from "ng-dynamic-component";For importing specific functionality:
import {
DynamicComponent,
DynamicIoDirective,
ComponentOutletIoDirective,
DynamicAttributesDirective,
InputsType,
OutputsType
} from "ng-dynamic-component";import { Component, Type } from '@angular/core';
import { DynamicComponent } from 'ng-dynamic-component';
@Component({
selector: 'app-example',
template: `
<ndc-dynamic
[ndcDynamicComponent]="selectedComponent"
[ndcDynamicInputs]="componentInputs"
[ndcDynamicOutputs]="componentOutputs"
(ndcDynamicCreated)="onComponentCreated($event)">
</ndc-dynamic>
`
})
export class ExampleComponent {
selectedComponent: Type<any> = MyDynamicComponent;
componentInputs = { title: 'Hello World', data: [1, 2, 3] };
componentOutputs = {
onSave: (event: any) => console.log('Saved:', event),
onCancel: () => console.log('Cancelled')
};
onComponentCreated(componentRef: ComponentRef<any>) {
console.log('Dynamic component created:', componentRef);
}
}import { ComponentOutletIoDirective } from 'ng-dynamic-component';
@Component({
template: `
<ng-container
*ngComponentOutlet="selectedComponent"
[ngComponentOutletNdcDynamicInputs]="inputs"
[ngComponentOutletNdcDynamicOutputs]="outputs">
</ng-container>
`
})
export class OutletExampleComponent {
selectedComponent = MyComponent;
inputs = { message: 'Hello' };
outputs = { onClick: (data: any) => this.handleClick(data) };
}ng-dynamic-component is built around several key architectural components:
DynamicComponent provides the main interface for creating components at runtimeDynamicIoDirective and related servicesNgComponentOutlet with additional capabilitiesDynamicAttributesDirectiveCore functionality for creating Angular components dynamically at runtime with full lifecycle support, custom injectors, and projected content.
@Component({
selector: 'ndc-dynamic',
standalone: true,
template: ''
})
export class DynamicComponent<C = unknown> implements OnChanges, DynamicComponentInjector {
@Input() ndcDynamicComponent?: Type<C> | null;
@Input() ndcDynamicInjector?: Injector | null;
@Input() ndcDynamicProviders?: StaticProvider[] | null;
@Input() ndcDynamicContent?: Node[][];
@Input() ndcDynamicNgModuleRef?: NgModuleRef<unknown>;
@Input() ndcDynamicEnvironmentInjector?: EnvironmentInjector | NgModuleRef<unknown>;
@Output() ndcDynamicCreated: EventEmitter<ComponentRef<C>>;
componentRef: ComponentRef<C> | null;
createDynamicComponent(): void;
}Type-safe system for binding inputs and outputs to dynamic components at runtime, supporting both function handlers and complex output expressions.
interface InputsType {
[k: string]: unknown;
}
interface OutputsType {
[k: string]: OutputExpression | undefined;
}
type OutputExpression = EventHandler | OutputWithArgs;
type EventHandler<T = unknown> = (event: T) => unknown;
interface OutputWithArgs {
handler: AnyFunction;
args?: unknown[];
}Directives that extend Angular's built-in NgComponentOutlet with dynamic input/output binding and component reference access.
@Directive({
selector: '[ngComponentOutlet]',
standalone: true,
exportAs: 'ndcComponentOutletInjector'
})
export class ComponentOutletInjectorDirective {
readonly componentRef: ComponentRef<unknown>;
}
@Directive({
selector: '[ngComponentOutletNdcDynamicInputs],[ngComponentOutletNdcDynamicOutputs]',
standalone: true,
exportAs: 'ndcDynamicIo'
})
export class ComponentOutletIoDirective implements DoCheck {
@Input() ngComponentOutletNdcDynamicInputs?: InputsType | null;
@Input() ngComponentOutletNdcDynamicOutputs?: OutputsType | null;
}System for dynamically setting and managing HTML attributes on component elements at runtime.
interface AttributesMap {
[key: string]: string;
}
@Directive({
selector: '[ndcDynamicAttributes],[ngComponentOutletNdcDynamicAttributes]',
standalone: true,
exportAs: 'ndcDynamicAttributes'
})
export class DynamicAttributesDirective implements DoCheck {
@Input() ndcDynamicAttributes?: AttributesMap | null;
@Input() ngComponentOutletNdcDynamicAttributes?: AttributesMap | null;
setAttribute(name: string, value: string, namespace?: string): void;
removeAttribute(name: string, namespace?: string): void;
}Advanced system for dynamically attaching directives to components at runtime with input/output binding support.
interface DynamicDirectiveDef<T> {
type: Type<T>;
inputs?: InputsType;
outputs?: OutputsType;
}
function dynamicDirectiveDef<T>(
type: Type<T>,
inputs?: InputsType,
outputs?: OutputsType
): DynamicDirectiveDef<T>;
interface DirectiveRef<T> {
instance: T;
type: Type<T>;
injector: Injector;
hostComponent: unknown;
hostView: ViewRef;
location: ElementRef;
changeDetectorRef: ChangeDetectorRef;
onDestroy: (callback: Function) => void;
}Essential services for component I/O management, reflection utilities, and dependency injection infrastructure.
interface DynamicComponentInjector {
componentRef: ComponentRef<unknown> | null;
}
const DynamicComponentInjectorToken: InjectionToken<DynamicComponentInjector>;
@Injectable({ providedIn: 'root' })
export class IoFactoryService {
create(
componentInjector: DynamicComponentInjector,
ioOptions?: IoServiceOptions & IoFactoryServiceOptions
): IoService;
}
@Injectable()
export class IoService implements OnDestroy {
update(inputs?: InputsType | null, outputs?: OutputsType | null): void;
}ng-dynamic-component supports both standalone components and NgModule-based applications:
import { DynamicComponent, DynamicIoDirective } from 'ng-dynamic-component';
@Component({
standalone: true,
imports: [DynamicComponent, DynamicIoDirective],
template: `<ndc-dynamic [ndcDynamicComponent]="comp"></ndc-dynamic>`
})
export class MyComponent { }import { DynamicModule } from 'ng-dynamic-component';
@NgModule({
imports: [DynamicModule],
// ...
})
export class MyModule { }For fine-grained control, import specific feature modules:
import {
DynamicModule, // Core dynamic component + I/O
DynamicIoModule, // Just I/O directives
DynamicAttributesModule, // Dynamic attributes only
DynamicDirectivesModule, // Dynamic directives only
ComponentOutletInjectorModule // NgComponentOutlet enhancements only
} from 'ng-dynamic-component';
@NgModule({
imports: [
DynamicModule, // Main module with all features
// OR import specific features:
// DynamicIoModule, // Dynamic I/O directives
// DynamicAttributesModule, // Dynamic attributes directive
// DynamicDirectivesModule, // Dynamic directives (experimental)
// ComponentOutletInjectorModule, // NgComponentOutlet enhancements
],
// ...
})
export class FeatureModule { }