کامپوننت های پویا (Dynamic Comp)
«کامپوننت پویا (Dynamic Component)» یعنی ساخت کامپوننت هنگام اجرا. این کار مثل ساخت قطعه لگو در لحظه است. سپس جاگذاری می کنی و ورودی می دهی. همچنین رویداد می گیری. برای ساده سازی، از *ngComponentOutlet هم می توان استفاده کرد.
مبانی کامپوننت پویا
با createComponent() کامپوننت را می سازی. سپس ورودی ها و خروجی ها را ست می کنی. اگر نیاز داشتی، میزبان را مشخص کن. در حالت ساده، با *ngComponentOutlet همان را سریع رندر کن.
import { bootstrapApplication } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { EventEmitter } from '@angular/core';
import { Output } from '@angular/core';
import { Input } from '@angular/core';
import { ElementRef } from '@angular/core';
import { ViewChild } from '@angular/core';
import { inject } from '@angular/core';
import { EnvironmentInjector } from '@angular/core';
import { ComponentRef } from '@angular/core';
import { createComponent } from '@angular/core';
@Component({
standalone: true,
template: `
<div style=\"padding:8px;border:1px solid #ddd;border-radius:6px;\">
<h4 style=\"margin:0 0 8px 0;\">{{ title }}</h4>
<button (click)=\"clicked.emit()\">Click</button>
</div>
`,
})
export class Card {
@Input() title = 'Card';
@Output() clicked = new EventEmitter<void>();
}
@Component({
selector: 'app-root',
standalone: true,
template: `
<h3>Dynamic createComponent()</h3>
<div #host style=\"min-height:60px;border:1px dashed #aaa;padding:8px;border-radius:6px;\"></div>
<div style=\"margin-top:8px;display:flex;gap:8px;flex-wrap:wrap;\">
<button (click)=\"mount()\">Mount</button>
<button (click)=\"update()\">Update input</button>
<button (click)=\"unmount()\">Unmount</button>
</div>
`,
})
export class App {
@ViewChild('host', { read: ElementRef }) host!: ElementRef<HTMLElement>;
env: EnvironmentInjector = inject(EnvironmentInjector);
ref: ComponentRef<Card> | null = null;
mount() {
if (this.ref) {
return;
}
this.ref = createComponent(Card, {
environmentInjector: this.env,
hostElement: this.host.nativeElement,
});
this.ref.setInput?.('title', 'Hello from Dynamic');
this.ref.instance.clicked.subscribe(() => alert('Card clicked'));
}
update() {
if (!this.ref) {
return;
}
const now = new Date().toLocaleTimeString();
this.ref.setInput?.('title', 'Updated Title ' + now);
}
unmount() {
this.ref?.destroy();
this.ref = null;
}
}
bootstrapApplication(App);
رندر سریع با *ngComponentOutlet
این دستور مثل «جاگذاری آماده» است. یک کامپوننت مستقل می دهی. سپس با inputs و outputs همان جا سیم کشی می کنی. بنابراین کد کم تر می نویسی.
import { bootstrapApplication } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { EventEmitter } from '@angular/core';
import { Output } from '@angular/core';
import { Input } from '@angular/core';
import { signal } from '@angular/core';
import { NgComponentOutlet } from '@angular/common';
@Component({
standalone: true,
template: `<button (click)=\"clicked.emit()\">{{ label }}</button>`,
})
export class ActionButton {
@Input() label = 'Do it';
@Output() clicked = new EventEmitter<void>();
}
@Component({
selector: 'app-root',
standalone: true,
imports: [NgComponentOutlet],
template: `
<h3>Selectorless via *ngComponentOutlet</h3>
<p>Clicks: {{ clicks() }}</p>
<ng-container *ngComponentOutlet=\"ActionButton; inputs: { label: 'Launch' }; outputs: { clicked: onClick }\"></ng-container>
`,
})
export class App {
ActionButton = ActionButton;
clicks = signal(0);
onClick = () => {
this.clicks.update(n => n + 1);
};
}
bootstrapApplication(App);
گام های عملی
- نیاز پویا را مشخص کن.
- برای کنترل کامل، createComponent() را استفاده کن.
- برای سادگی، از *ngComponentOutlet کمک بگیر.
- خروجی ها را تمیز لغو یا نابود کن.
نکته: همیشه بعد از حذف، destroy() را صدا بزن. بنابراین نشتی حافظه رخ نمی دهد.
جمع بندی سریع
- createComponent() = کنترل کامل.
- *ngComponentOutlet = سادگی سریع.
- ورودی/خروجی را دقیق سیم کشی کن.
- پاک سازی را فراموش نکن.
بیشتر بخوان: کنترل جریان، سیگنال ها، و کامپوننت پویا انگولار.