Structural Directive
Directive
- Attribute directive
- Structural directive
디렉티브는 굉장히 자주 보는 문법인데 사실 정리가 잘 안되면 그냥 잘 모른 체 지나가기 쉽다
이 기회에 Structural directive에 대해 정리해보자
Structural Directive
Structural directives are directives which change the DOM layout by adding and removing DOM elements.
구조 디렉티브는 DOM 요소를 동적으로 보여줄지 말지 결정할 수 있는 문법 도구라 할 수 있다.
Built-in structural directive: NgIf, NgForOf, NgSwitch
Structural Directive Shorthand
접두사로 *ngIf와 같이 * (asterisk)를 사용한다.
Angular는 * 를 elements를 감싸는 ng-template 형태로 변환한다.
<div *ngIf="hero" class="name">{{hero.name}}</div>
이 때 *ngIf => [ngIf], square bracket으로 변해 property binding이 된다 !!
이 부분이 많이 놀라웠는데 내가 항상 사용하던 HTML 템플릿에서 자식 component에 property 넘겨주고 component단에서 @input()으로 받아 사용하는 문법과 완전히 동일해지기 때문이다. 즉 *ngIf는 결국 [ngIf]로 property를 넘겨주고 @Input() ngIf로 사용하는 property-binding와 같다는 것이다 !
<ng-template [ngIf]="hero">
<div class="name">{{hero.name}}</div>
</ng-template>
주의해야할 점은 Angular가 실제로 <ng-template> 을 만들지 않고 <div>만 render 한다는 것이다.
<div _ngcontent-c0>Mr. Nice</div>
ngFor의 예시는 다음과 같다
<div
*ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById"
[class.odd]="odd">
({{i}}) {{hero.name}}
</div>
<ng-template ngFor let-hero [ngForOf]="heroes"
let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
<div [class.odd]="odd">
({{i}}) {{hero.name}}
</div>
</ng-template>
let hero -> let-hero로, of가 [ngForOf]로 변경 되었다.
One Structural Directive per Element
You may apply only one structural directive to an element.
한 element 내에서 ngIf나 ngFor을 동시에 쓸 수 없다.
이럴 경우 ng-container로 감싸서 ngIf를 적용시키고 내부 element에서 ngFor을 사용하면 된다
Creating a structural directive
결국 structural directive를 만들어 쓸 수 있어야 한다.
ngIf와 반대인 UnlessDirective를 만들어보자. 이 디렉티브는 false일 때 contents를 보여준다.
// src/app/app.component.html (appUnless-1)
<p *appUnless="condition">Show this sentence unless the condition is true.</p>
//src/app/unless.directive.ts (skeleton)
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef) { }
}
CSS selector로 appUnless를 특정하면 template에서 directive를 찾을 수 있다.
"appUnless" 였다면 appUnless라는 component 요소를 찾는 selector일 것이다. 그러므로 directive를 찾기 위해서는 square bracket, []를 사용하도록 하자
그리고 Input, TemplateRef, ViewContainerRef를 import 후 constructor에서 주입하자.
이후 appUnless Input property를 setter로 추가하자
@Input() set appUnless(condition: boolean) {
if (!condition && !this.hasView) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.hasView = true;
} else if (condition && this.hasView) {
this.viewContainer.clear();
this.hasView = false;
}
}
Angular는 condition value가 바뀔 때 마다 appUnless property를 바꾼다.
- condition === false 인 경우, Angular는 이전에 view를 만들지 않았기 때문에 setter는 view container가 template에서 view를 만들도록 한다.
- condition === true인 경우, 이미 view가 보여지고 있기 때문에, setter가 container를 clear하여 없앤다.
참조: Angular 공식 문서 - Structural-directive
'프로그래밍 > Angular' 카테고리의 다른 글
Udemy - Angular 강의 - 기억할만한 부분 정리 (0) | 2023.03.18 |
---|
댓글