Dynamic Components
Using ViewContainerRef
Section titled “Using ViewContainerRef”import { Component, viewChild, ViewContainerRef, inject } from '@angular/core';import { UserComponent } from './user.component';
@Component({ selector: 'app-container', standalone: true, template: ` <button (click)="loadComponent()">Load Component</button> <ng-container #container></ng-container> `})export class ContainerComponent { // Signal-based query - no lifecycle hook needed container = viewChild.required('container', { read: ViewContainerRef });
loadComponent() { const vcr = this.container(); // Access as signal vcr.clear(); const componentRef = vcr.createComponent(UserComponent);
// Set inputs (for signal inputs, use .set()) componentRef.setInput('data', 'Dynamic data');
// Subscribe to outputs componentRef.instance.dataEvent.subscribe((value) => { console.log(value); }); }}Dynamic Component with Data
Section titled “Dynamic Component with Data”import { Component, ComponentRef, viewChild, ViewContainerRef, Type } from '@angular/core';
@Component({ selector: 'app-dynamic-loader', standalone: true, template: `<ng-container #outlet></ng-container>`})export class DynamicLoaderComponent { // Signal-based query outlet = viewChild.required('outlet', { read: ViewContainerRef });
loadComponent(componentType: Type<any>, data: any) { const vcr = this.outlet(); // Access as signal const ref = vcr.createComponent(componentType);
// For signal inputs, use setInput() Object.keys(data).forEach(key => { ref.setInput(key, data[key]); });
return ref; }
clearComponents() { this.outlet().clear(); // Access as signal }}Portal (CDK)
Section titled “Portal (CDK)”import { Component, TemplateRef, viewChild } from '@angular/core';import { CdkPortal, DomPortalOutlet } from '@angular/cdk/portal';
@Component({ selector: 'app-portal-example', standalone: true, imports: [CdkPortal], template: ` <ng-template cdkPortal #portal> <p>Portal content</p> </ng-template> `})export class PortalExampleComponent { // Signal-based query portal = viewChild.required<CdkPortal>('portal');
attachToBody() { const outlet = new DomPortalOutlet(document.body); outlet.attach(this.portal()); // Access as signal }}Dynamic Dialog Example
Section titled “Dynamic Dialog Example”@Injectable({ providedIn: 'root' })export class DialogService { private vcr = inject(ViewContainerRef);
open(component: Type<any>, data?: any): ComponentRef<any> { const ref = this.vcr.createComponent(component); if (data) { Object.assign(ref.instance, data); } return ref; }
close(ref: ComponentRef<any>) { ref.destroy(); }}Lazy Load Component
Section titled “Lazy Load Component”async loadLazyComponent() { const { LazyComponent } = await import('./lazy.component'); this.container.createComponent(LazyComponent);}Best Practices
Section titled “Best Practices”- Clear components when done:
componentRef.destroy() - Use CDK Portal for complex scenarios
- Prefer declarative approaches (
*ngIf,*ngFor) when possible - Use for: modals, tooltips, dynamic forms, plugin systems

