디렉티브란?
전역에서 공통으로 사용하는 기능을 컴포넌트에서 분리하여 구현한 것
디렉티브는 컴포넌트와 달리 자식을 가질 수 없다.
@Directive 데코레이터로 장식된 클래스이다.
Angular에서는 크게 3가지 디렉티브를 제공한다.
- 컴포넌트 디렉티브(chapter7) : 컴포넌트 템플릿을 표시하기 위한 디렉티브이다.
- 어트리뷰트 디렉티브 : ngClass, ngStyle 같이 Dom 요소의 어트리뷰트로 사용하여 해당요소의 모양 ,동작을 제어
- 구조 디렉티브 : ngIf, ngFor, ngSwitch 같이 dom 의 구조를 변경하는 디렉티브
이 외에도 사용자 정의 디렉티브가 있다.
사용자 정의 디렉티브
- 디렉티브를 생성한다.
1 | ng g d textBlue |
- 생성된 디렉티브를 수정한다.
1 | import { Directive, ElementRef } from '@angular/core'; |
selector 프로퍼티에는 css 셀렉터 문법과 동일하게 디렉티브가 적용되는 조건을 설정 할 수 있다.
생성자(constructor)에 ElementRef 타입의 인스턴스가 주입되었다.
그러나, ElementRef로 dom에 직접 접근하기보다는 Renderer2 클래스로 Dom에 직접 접근하지 않으면서 네이티브 요소를 조작하는 방법을 권장한다.
- app.module.ts에 디렉티브를 추가한다.(보통 cli로 생성하면 자동으로 등록된다.)
1 | ... |
- 디렉티브를 모듈에 등록하면 컴포넌트에서 사용가능하다. 디렉티브를 적용해본다.
1 | import { Component } from '@angular/core'; |
p 태그가 파란색으로 바뀜
이벤트 처리
mouseenter 이벤트가 발생하면 텍스트를 파란색으로, mouseleave 되면 파란색을 취소하도록 디렉티브의 이벤트 기능을 추가한 경우이다.
1 | import { Directive, ElementRef, Renderer2, HostListener } from '@angular/core'; |
ElementRef에 접근 제한자 private를 추가한다.
@HostListener 데코레이터를 사용하여 호스트 요소의 이벤트에 대한 핸들러를 정의한다.
사용자 정의 구조 디렉티브
- 새로운 프로젝트와 새로운 디렉티브를 생성한다.
1 | ng new custom-structure-directive -t -s -S |
- templateRef와 viewContainer를 import 한 후 디렉티브를 수정한다.
1 | import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core'; |
1 | import { Component } from '@angular/core'; |
1) 프로퍼티 바인딩에 의해 전달된 myNgIf 디렉티브 상태값이 true이면 viewContainerRef의 createEmbeddedView 메소드에 호스트( app.component)의 ng-template으로 래핑된 요소를 의미하는 templateRef 객체를 인자로 전달하여 뷰에 추가한다.
2) 위와 같은 방식으로 clear 하여 뷰에서 완전히 제거한다.
ng-template 디렉티브
ngIf, ngFor, ngSwitch 같은 빌트인 구조 디렉티브는 디렉티브 이름 앞에 붙은 *기호에 의해 ng-template으로 변환된다.
예를 들어
<element *nglf=”expression”>
ngIf 앞에 붙은 * 기호는 아래 구문으로 변환된다.
1 | <ng-template [ngIf]="expression"> |
angular 는 *ngIf를 만나면 호스트 요소를 ng-template 디렉티브로 래핑하고 ngIf를 프로퍼티 바인딩으로 변환한다. ng-template 디렉티브는 컴포넌트 템플릿의 일부로서 주석처리 되어 뷰에 랜더링되지 않다가 ngIf 바인딩 값이 true 이면 뷰에 랜더링된다.
이 때 ngIf는 TemplateRef와 ViewContainerRef 의 인스턴스를 사용하여 ng-template 디렉티브로 래핑된 요소를 랜더링하거나 dom에서 제거한다.
위의 예제에서도 myNgIf가 ngIf와 같은 역할을 한다. myNgIf 디렉티브에 바인딩된 값을 평가하여 ViewContainerRef의 createEmbeddedView 메소드 또는 clear 메소드를 호출하여 ng-template의 랜더링 여부를 결정한다.
templateRef와 ViewContainerRef
templateRef는 ng-template 로 래핑된 요소를 가리키는 객체를 생성한다.
ViewContainerRef는 하나 이상의 뷰를 포함시킬 수 있는 컨테이너이다. 즉 ng-template 디렉티브로 래핑된 요소를 dom에 삽입하기 위해 필요한 컨테이너 로써 메소드를 통해 새로운 요소를 DOM에 추가한다.
ng-container 디렉티브
단순히 디렉티브를 선언하기 위해 태그가 필요할 경우 사용한다.
ng-template는 문법을 사용할 수 없지만, ng-container는 *문법(ex)ngIf) 등이 사용가능하다.
일반적으로 angular는 같은 요소에 하나 이상의 구조 디렉티브 사용을 금지하므로, 이런 경우가 필요할 때 ng-cotainer 요소를 사용한다.
1 | <!--같은 요소에 ngFor문과 ngIf 문을 사용하고 싶을 때 --> |