Structural directive (ตัวที่มี * เช่น *ngIf/*ngFor) เปลี่ยนแปลง DOM โดย คือ syntactic sugar — เบื้องหลัง Angular จะห่อองค์ประกอบในแท็ก และ directive นั้นจะควบคุมว่าจะแสดงผล template นั้นหรือไม่และอย่างไร
Structural directive (ตัวที่มี * เช่น *ngIf/*ngFor) เปลี่ยนแปลง DOM โดย คือ syntactic sugar — เบื้องหลัง Angular จะห่อองค์ประกอบในแท็ก และ directive นั้นจะควบคุมว่าจะแสดงผล template นั้นหรือไม่และอย่างไร
*<ng-template><!-- what you write -->
<p *ngIf="isVisible">Hello</p>
<!-- what Angular actually does -->
<ng-template [ngIf]="isVisible">
<p>Hello</p>
</ng-template>
* บอก Angular ว่า: "ห่อองค์ประกอบนี้ในแท็ก template และให้ directive ตัดสินใจว่าจะเพิ่มมันลงใน DOM เมื่อไร" <ng-template> คือมาร์กอัปที่ไม่มีชีวิตจนกว่า directive จะสร้างมันขึ้นมา
import { Directive, Input, TemplateRef, ViewContainerRef } from "@angular/core";
@Directive({ selector: "[appUnless]" }) // *appUnless = "the opposite of ngIf"
export class UnlessDirective {
constructor(
private templateRef: TemplateRef<any>, // the wrapped <ng-template>
private viewContainer: ViewContainerRef, // where to render it
) {}
@Input() set appUnless(condition: boolean) {
if (!condition) {
this.viewContainer.createEmbeddedView(this.templateRef); // render it
} else {
this.viewContainer.clear(); // remove it
}
}
}
// usage: <p *appUnless="isHidden">Shown when isHidden is false</p>
สองส่วนที่ injected นั้นเป็นกุญแจ: TemplateRef คือแท็ก template ขององค์ประกอบ ("อะไรที่จะแสดงผล") และ ViewContainerRef คือตำแหน่งใน DOM ("ตรงไหน") Directive นั้นจะเรียก createEmbeddedView เพื่อเพิ่มองค์ประกอบหรือ clear เพื่อลบมัน
<!-- newer Angular replaces *ngIf/*ngFor with built-in block syntax -->
@if (isVisible) { <p>Hello</p> } @else { <p>Hidden</p> }
@for (item of items; track item.id) { <li>{{ item.name }}</li> }
Syntax ที่ใหม่กว่านี้นั้นอ่านง่ายและสมรรถนะดีกว่า แต่แนวคิดการเพิ่ม/ลบที่พื้นฐานนั้นเหมือนกัน
การเข้าใจการ desugaring * → <ng-template> ทำให้ชัดเจนว่า *ngIf/*ngFor เพิ่มและลบ DOM อย่างไร และช่วยให้คุณสร้าง custom structural directive (ใช้ TemplateRef + ViewContainerRef) สำหรับการควบคุม template ขั้นสูง — เช่น การแสดงผลตามสิทธิ์ repeater ที่กำหนดเอง หรือ stamping แบบเกียจคร้าน
นอกจากนี้ยังอธิบายว่าทำไมคุณไม่สามารถใส่ structural directive สองตัว (*ngIf และ *ngFor) บนองค์ประกอบเดียว: แต่ละตัวต้องมี template wrapper ของตัวเอง