구조 directive(*가 붙은 것들, 예: *ngIf/*ngFor)는 하여 DOM을 변경합니다. 는 문법적 설탕(syntactic sugar)입니다. 내부적으로 Angular는 요소를 으로 감싸고, directive가 그 템플릿이 렌더링될지/어떻게 렌더링될지를 제어합니다.
*<ng-template><!-- 당신이 작성하는 것 -->
<p *ngIf="isVisible">Hello</p>
<!-- Angular가 실제로 하는 것 -->
<ng-template [ngIf]="isVisible">
<p>Hello</p>
</ng-template>
*는 Angular에게 "이 요소를 템플릿으로 감싸고, directive가 언제 그것을 DOM에 찍어낼지 결정하게 하라"고 말합니다. <ng-template>은 directive가 인스턴스화하기 전까지 렌더링되지 않는 비활성 마크업 덩어리입니다.
import { Directive, Input, TemplateRef, ViewContainerRef } from "@angular/core";
@Directive({ selector: "[appUnless]" }) // *appUnless = "ngIf의 반대"
export class UnlessDirective {
constructor(
private templateRef: TemplateRef<any>, // 감싸진 <ng-template>
private viewContainer: ViewContainerRef, // 렌더링할 위치
) {}
@Input() set appUnless(condition: boolean) {
if (!condition) {
this.viewContainer.createEmbeddedView(this.templateRef); // 렌더링
} else {
this.viewContainer.clear(); // 제거
}
}
}
// 사용: <p *appUnless="isHidden">isHidden이 false일 때 표시됨</p>
주입되는 두 조각이 핵심입니다. **TemplateRef**는 요소의 템플릿("무엇을 렌더링할지")이고, **ViewContainerRef**는 DOM 내 위치("어디에")입니다. directive는 요소를 추가하기 위해 createEmbeddedView를, 제거하기 위해 clear를 호출합니다.
<!-- 최신 Angular는 *ngIf/*ngFor를 내장 블록 구문으로 대체한다 -->
@if (isVisible) { <p>Hello</p> } @else { <p>Hidden</p> }
@for (item of items; track item.id) { <li>{{ item.name }}</li> }
이 새로운 구문은 더 읽기 쉽고 성능이 좋지만, 기저의 추가/제거 개념은 동일합니다.
* → <ng-template> 변환을 이해하면 *ngIf/*ngFor가 어떻게 DOM을 추가/제거하는지 명료해지고, 고급 템플릿 제어를 위한 커스텀 구조 directive(TemplateRef + ViewContainerRef 사용)를 만들 수 있습니다. 예: 권한 기반 렌더링, 커스텀 반복기, lazy 찍어내기.
또한 한 요소에 두 개의 구조 directive(*ngIf와 *ngFor)를 둘 수 없는 이유도 명확해집니다. 각각 자신만의 템플릿 래퍼가 필요하기 때문입니다.
주니어부터 시니어까지 상세한 답변이 포함된 IT 면접 질문 라이브러리.
후원하기