본문 바로가기
프로그래밍/Angular

Directive - Structual directive, 구조 디렉티브

by Dean30 2023. 3. 5.
728x90

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

728x90

'프로그래밍 > Angular' 카테고리의 다른 글

Udemy - Angular 강의 - 기억할만한 부분 정리  (0) 2023.03.18

댓글