CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ng-dynamic-component

Dynamic components with full life-cycle support for inputs and outputs

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

dynamic-component.mddocs/

Dynamic Component Creation

Core functionality for creating Angular components dynamically at runtime with full lifecycle support, custom injectors, and projected content.

Capabilities

DynamicComponent

The main component for dynamically creating other Angular components at runtime.

/**
 * Main component for dynamically creating other Angular components
 * Supports full component lifecycle, custom injection, and projected content
 */
@Component({
  selector: 'ndc-dynamic',
  standalone: true,
  template: '',
  providers: [
    { provide: DynamicComponentInjectorToken, useExisting: DynamicComponent }
  ]
})
export class DynamicComponent<C = unknown> implements OnChanges, DynamicComponentInjector {
  /** The component type to create dynamically */
  @Input() ndcDynamicComponent?: Type<C> | null;
  
  /** Custom injector for the dynamic component */
  @Input() ndcDynamicInjector?: Injector | null;
  
  /** Additional providers for the dynamic component */
  @Input() ndcDynamicProviders?: StaticProvider[] | null;
  
  /** Projected content (projectable nodes) for content projection */
  @Input() ndcDynamicContent?: Node[][];
  
  /** NgModule reference for the component (for legacy non-standalone components) */
  @Input() ndcDynamicNgModuleRef?: NgModuleRef<unknown>;
  
  /** Environment injector for standalone components */
  @Input() ndcDynamicEnvironmentInjector?: EnvironmentInjector | NgModuleRef<unknown>;
  
  /** Emitted when a component is created */
  @Output() ndcDynamicCreated: EventEmitter<ComponentRef<C>>;
  
  /** Reference to the currently created component */
  componentRef: ComponentRef<C> | null;
  
  /** Manually trigger component creation */
  createDynamicComponent(): void;
}

Usage Examples:

import { Component, Type, ComponentRef, Injector } from '@angular/core';
import { DynamicComponent } from 'ng-dynamic-component';

// Basic dynamic component creation
@Component({
  selector: 'app-basic-example',
  template: `
    <ndc-dynamic 
      [ndcDynamicComponent]="selectedComponent"
      (ndcDynamicCreated)="onComponentCreated($event)">
    </ndc-dynamic>
  `
})
export class BasicExampleComponent {
  selectedComponent: Type<any> = MyDynamicComponent;

  onComponentCreated(componentRef: ComponentRef<any>) {
    // Access the component instance
    console.log('Component created:', componentRef.instance);
    
    // Set inputs directly on the component
    componentRef.instance.title = 'Dynamic Title';
    
    // Trigger change detection
    componentRef.changeDetectorRef.detectChanges();
  }
}

// Advanced usage with custom injector and providers
@Component({
  selector: 'app-advanced-example',
  template: `
    <ndc-dynamic 
      [ndcDynamicComponent]="componentType"
      [ndcDynamicInjector]="customInjector"
      [ndcDynamicProviders]="providers"
      [ndcDynamicContent]="projectedContent"
      (ndcDynamicCreated)="handleCreated($event)">
    </ndc-dynamic>
  `
})
export class AdvancedExampleComponent {
  componentType = CustomComponent;
  customInjector?: Injector;
  providers = [
    { provide: 'CONFIG', useValue: { apiUrl: 'https://api.example.com' } },
    { provide: MyService, useClass: MyService }
  ];
  projectedContent?: Node[][];

  constructor(private injector: Injector) {
    // Create custom injector
    this.customInjector = Injector.create({
      providers: [
        { provide: 'CUSTOM_TOKEN', useValue: 'custom-value' }
      ],
      parent: this.injector
    });
  }

  handleCreated(componentRef: ComponentRef<CustomComponent>) {
    // Component is created with custom injection context
    componentRef.instance.initialize();
  }
}

// Content projection example
@Component({
  selector: 'app-projection-example',
  template: `
    <ndc-dynamic 
      [ndcDynamicComponent]="wrapperComponent"
      [ndcDynamicContent]="contentNodes">
    </ndc-dynamic>
  `
})
export class ProjectionExampleComponent implements AfterViewInit {
  wrapperComponent = WrapperComponent;
  contentNodes?: Node[][];

  @ViewChild('content', { read: ElementRef }) contentEl!: ElementRef;

  ngAfterViewInit() {
    // Create content to project
    this.contentNodes = [
      [this.contentEl.nativeElement.childNodes[0]]
    ];
  }
}

Component Type Switching

Dynamically switch between different component types:

@Component({
  template: `
    <button (click)="switchComponent()">Switch Component</button>
    
    <ndc-dynamic 
      [ndcDynamicComponent]="currentComponent"
      (ndcDynamicCreated)="onCreated($event)">
    </ndc-dynamic>
  `
})
export class ComponentSwitcherComponent {
  private components = [ComponentA, ComponentB, ComponentC];
  private currentIndex = 0;
  
  get currentComponent() {
    return this.components[this.currentIndex];
  }

  switchComponent() {
    this.currentIndex = (this.currentIndex + 1) % this.components.length;
  }

  onCreated(componentRef: ComponentRef<any>) {
    console.log('Switched to:', componentRef.componentType.name);
  }
}

Working with Standalone Components

For standalone components, use the environment injector:

import { EnvironmentInjector } from '@angular/core';

@Component({
  template: `
    <ndc-dynamic 
      [ndcDynamicComponent]="standaloneComponent"
      [ndcDynamicEnvironmentInjector]="environmentInjector">
    </ndc-dynamic>
  `
})
export class StandaloneExampleComponent {
  standaloneComponent = MyStandaloneComponent;

  constructor(public environmentInjector: EnvironmentInjector) {}
}

Integration with Dynamic I/O

Combine with dynamic input/output directives for complete functionality:

import { DynamicComponent, DynamicIoDirective } from 'ng-dynamic-component';

@Component({
  standalone: true,
  imports: [DynamicComponent, DynamicIoDirective],
  template: `
    <ndc-dynamic 
      [ndcDynamicComponent]="component"
      [ndcDynamicInputs]="inputs"
      [ndcDynamicOutputs]="outputs"
      (ndcDynamicCreated)="onCreated($event)">
    </ndc-dynamic>
  `
})
export class FullExampleComponent {
  component = MyComponent;
  inputs = { title: 'Hello', data: [1, 2, 3] };
  outputs = {
    onSave: (data: any) => console.log('Saved:', data),
    onDelete: () => console.log('Deleted')
  };

  onCreated(componentRef: ComponentRef<any>) {
    // Component is created with inputs/outputs bound
  }
}

Types

/** Interface for objects that can provide ComponentRef access */
interface DynamicComponentInjector {
  componentRef: ComponentRef<unknown> | null;
}

/** Injection token for DynamicComponentInjector */
const DynamicComponentInjectorToken: InjectionToken<DynamicComponentInjector>;

docs

component-outlet.md

core-services.md

dynamic-attributes.md

dynamic-component.md

dynamic-directives.md

index.md

input-output.md

tile.json