/ ANGULAR

Angular 강좌(18) - Directive

Angular 강좌는 여러 절로 구성되어 있습니다.


Directive

이번 포스트에서는 Angular의 Directive에 대해서 알아보겠습니다. 지금까지 예제를 작성하면서 여러 directive를 사용해 왔는데요. 그에 대해서 조금 더 정리를 해 보려 합니다.

Directive는 DOM의 모양이나 동작을 지시하기 위한 명령이라고 생각하시면 됩니다. 크게 HTML Element형태로 사용되거나 Element의 attribute의 형태로 사용되게 됩니다. 예를 들면 우리가 사용했던 ngIf 같은 attribute를 떠올리시면 됩니다. Routing에서 사용했던 <router-outlet></router-outlet> Element 역시 directive입니다.

이렇게 directive는 DOM을 제어하기 위한 용도로 사용되는데 DOM을 제어하기 위해서 우리는 지금까지 Component를 이용했었습니다. Component로 제어하면 되지 굳이 directive로 DOM을 제어할 필요가 있느냐 하는 의문이 들 수 있습니다. 하지만 Component는 원칙적으로 자신이 rendering하는 View에 대해서만 관심이 있습니다. 여러 View들이 공통적으로 사용하는 Element나 Element의 attribute같은 것들을 따로 directive로 지정해 사용하면 SRP관점에서 봤을 때도 타당하고 Component의 복잡도를 낮출 수 있으며 유지보수와 같은 관리적인 측면에서도 더 나은 형태로 구현이 가능합니다.

Component 역시 큰 의미에서 directive입니다. Component는 directive이면서 View를 가지고 있고 자식 Component 또한 가질 수 있습니다. 하지만 directive는 View를 가지고 있지 않고 자식 directive 또한 가질 수 없습니다.

Directive는 크게 다음과 같은 4가지 종류로 구분 할 수 있습니다.

  • Component Directive

    우리가 알고 있는 Component입니다. selector에서 우리가 directive를 지정해 사용하게 됩니다.


  • Attribute Directive

    HTML Element의 Attribute로 사용됩니다. built-in 형태로는 ngClass 같은 것들이 있습니다.


  • Structural Directive

    DOM의 구성을 제어하기 위한 directive로 ngIf , ngFor, ngSwitch 등이 있습니다.


  • Custom Directive

    built-in 형태로 만들어진 directive가 아닌 직접 만들어서 사용하는 directive를 지칭합니다.


이 중 Component에 대해서는 많이 사용해 봤으니 Structural Directive와 Custom Directive에 대해서 알아보도록 하겠습니다.


Structural Directive

우리 예제에서도 사용했던 ngIf, ngFor등을 지칭합니다. 단, 이것들은 built-in된 형태입니다. 이런 구조적 directive를 우리가 직접 만들어서 사용할 수도 있습니다. ngIf와 ngFor를 사용하실 때 몇가지 알아두셔야 하는 사항이 있습니다.

일반적으로 다음과 같이 코드처리 합니다.

<div *ngIf="hero" class="name"></div>

hero가 null과 undefined가 아니면 <div>를 DOM에 추가하고 interpolation을 이용해 값을 출력하는 코드입니다.

이 코드는 사실 다음과 같이 변형되어서 실행됩니다.

<ng-template [ngIf]="hero">
  <div class="name"></div>
</ng-template>

ng-template을 이용해서 조건을 통해 <div>의 처리를 결정합니다.

비교해서 보셔야 할 것으로 ng-container가 있습니다. 위의 코드는 다음의 코드로 표현이 가능합니다.

<ng-container *ngIf="hero">
  <div class="name"></div>
</ng-container>

Angular는 동일한 Element에 두개 이상의 *ngIf, *ngFor, *ngSwitch를 사용할 수 없습니다. for문을 돌리면서 if문을 이용해 비교하고 싶은 경우에는 문제가 됩니다. 이 같은 경우를 해결하기 위해 ng-container를 제공하는 것이라 보시면 됩니다.


Custom Directive

기존에 만들었던 mySearchProject에 간단하게 Custom Directive를 추가하고 어떻게 이용하는지 살펴보도록 하겠습니다.

command 창을 열고 다음의 명령을 실행해서 directive를 하나 생성합니다. 현재 command 창의 working directory는 src/app 입니다.

ng generate directive textColor

두개의 파일이 생성됩니다. Angular CLI의 이름규칙에 의해 text-color.directive.ts 라는 이름의 파일이 생성됩니다.

그 내용을 다음과 같이 수정합니다.

import {Directive, ElementRef, Renderer2} from '@angular/core';

@Directive({
  selector: '[myColor]'
})
export class TextColorDirective {

  constructor(elementref: ElementRef, renderer: Renderer2) {
    renderer.setStyle(elementref.nativeElement,'color','darkred');
  }

}

위의 directive 내용은 HTML Element의 속성으로 myColor 가 사용되었을 경우 해당 Element를 DOM에 rendering 할 때 글자색을 darkred로 설정하라는 것입니다.

이렇게 directive를 생성하면 사용하기 위해서 Root Module에 등록해야 합니다. Angular CLI를 이용했기 때문에 이미 등록이 되어 있습니다. 이제 실제 해당 directive가 정상적으로 동작하는지 확인해보면 될 듯 합니다.

pages/home 폴더에 있는 home.component.html을 수정해서 해당 directive를 사용해 보죠.

<h1>HOME</h1>
<hr>
<p myColor>이 Web Application은 Angular 강좌를 위한 Test App입니다.
<p>이 강좌는 다음의 내용을 포함합니다. </p>
<ul>
  <li>Angular의 기본 구조</li>
  <li>Angular CLI</li>
  <li>Component</li>
  <li>Template - Template Reference Variable</li>
...
...
...  

위와 같이 myColor라는 directive를 사용할 수 있습니다. 해당 P Element의 text 글자는 darkred로 출력되겠네요.

가장 직관적인 예를 들기 위해 text color를 변경하는걸로 처리를 했는데 그 외 DOM을 제어하는 다른 기능들도 할 수 있습니다.

이번에는 이벤트 처리를 한번 해 보죠. 위의 예에서 해당 P Element를 클릭했을 때 alert() 이 수행되게 할려면 다음과 같이 처리하시면 됩니다.

import {Directive, ElementRef, HostListener, Renderer2} from '@angular/core';

@Directive({
  selector: '[myColor]'
})
export class TextColorDirective {

  @HostListener('click', ['$event']) elementClick(e) {
    // e안에는 event객체가 들어온다.
    // this는 directive 객체를 지칭.
    alert(e.srcElement.innerHTML)
  }

  constructor(elementref: ElementRef, renderer: Renderer2) {
    renderer.setStyle(elementref.nativeElement,'color','darkred');
  }

}

이벤트를 처리하기 위해 @HostListener decorator를 이용했습니다. 여기서 host라는 표현이 나오는데 지금 우리 예제에서 myColor 속성을 적용한 HTML Element를 host라고 지칭합니다.

이벤트 객체를 얻기 위해 처리하는 부분을 조심해서 보시면 됩니다.

추가적으로 @Input decorator를 이용해서 directive가 값을 전달 받을 수 있습니다. 원래 @Input은 부모 Component가 자식 Component 에게 데이터를 전달해 주기 위해 사용했었는데 directive에게도 값을 전달 할 수 있습니다. 사용하는 Component때 했던 것과 동일합니다.

이번 포스트는 Directive에 대해서 정리해보았습니다. 더 많은 기능이 있지만 기본적으로 이런 용도로 사용된다는 정도만 알고 계시면 될 듯 합니다.

End.


Angular 강좌는 아래의 책과 사이트를 참조했습니다. 조금 더 자세한 사항을 알고 싶으시면 해당 사이트를 방문하세요!!