TIL_171109 Angular Component - Template, Date Binding, Built-in directive

앵귤러안에서는 DOM을 써도 되지만, 쓰는 순간 앵귤러의 의미를 잃어버린다.
되도록 쓰지 않도록 하나, Pure Javascript를 잊어버리지 않도록 유의*

용어정리

  1. Model : 애플리케이션에서 사용되는 데이터 형식 과 이를 컨트롤하는 로직 (비즈니스/유효성 검사)
  2. View : 사용자에게 model을 표시하는 것
  • 구문 vs 표현식
    • 구문: 시스템을 변경할 수 있고 ;으로 끝남
    • 표현식: 값, 변수, 연산자의 조합으로 연산을 통해 하나의 값을 만듬

변화 감지

앵귤러는 Zone.js 라이브러리를 통해 아래의 변화를 감지

  1. DOM 이벤트
  2. Timer의 tick 이벤트
  3. Ajax / Promise

연결된 바인딩이 어떠한 상황에 변화하는가? (Zone.js가 체크하는 지점)

  • 기본자료형은 pass by value기 때문에 메모리주소가 바뀌는 순간 변경을 감지
  • 객체는 pass by reference기 때문에 메모리주소가 재할당되어야 변경을 감지
    즉, 값이 바뀌지 않았다 하더라도 메모리주소가 변경되면 변화감지가 일어남
    *filter와 같이 원본 배열은 그대로 두는 것은 변화감지가 일어나지 않음

Template Syntax

템플릿과 컴포넌트 클래스간의 데이터 공유를 위한 문법 (데이터 바인딩)

Data Binding

1. 인터폴레이션

  • 표현식을 사용 (연산자 제외)
  • 템플릿에는 하나의 값이 들어가고, 컴포넌트 클래스의 프로퍼티를 변경할 수 있는 연산자는 사용 금지
  • 당연히 재할당을 지정하는 행위 역시 금지
  • 프로퍼티 바인딩의 syntax sugar

2. 프로퍼티 바인딩*

  • [property]=”expression”
  • 표현식 평가 결과가 DOM 프로퍼티에 바인딩됨
  • 즉, 컴파일 됐을때 html 마크업상으론 표현이 X, 오롯이 DOM에만
  • 따라서 해당하는 태그의 DOM 프로퍼티가 있는지를 확인하고 바인딩을 사용해야 함

3. 어트리뷰트 바인딩

  • [attr.attribute-name]=”expression”
  • 보통 프로퍼티 바인딩으로 해결하지 못할때 사용 (td colspan 등)

[참고] DOM 프로퍼티 vs HTML 어트리뷰트*

HTML의 어트리뷰트는 DOM구조에서
(1) 대응하는 DOM의 프로퍼티와
(2) DOM의 ‘attribute’ 프로퍼티에 유사배열 형태로 저장

예를 들어 HTML input태그에 선언된 어트리뷰트는 DOM의 input element의 attribute 프로퍼티 에 유사배열형태로 저장 [id, type, value]

  • 이 유사배열에 있는 value값은 초기값(선언한 값)을 가지고 있음
  • 유저가 입력값을 바꾸면 바뀐 value값은 DOM property리스트의 value(대응하는 프로퍼티)가 저장

즉, DOM의 프로퍼티와 HTML의 어트리뷰트가 언제나 1:1로 매핑되는 것은 아님

  • 서로에게 대응하는 어트리뷰트와 프로퍼티가 없을 수 있음 (class / classList)
  • 같은 이름, 서로에게 대응하는 것이 있어도 다르게 동작할 수 있음 (value 예)
1
2
3
4
5
<!-- 프로퍼티 바인딩의 변환 결과 -->
<input id="user" type="text">
<!-- 어트리뷰트 바인딩의 변환 결과 -->
<input id="user" type="text" value="name">

4. 클래스 바인딩

  • [class.class-name]=”expression”
  • 중복되는 경우 true면 병합되고 false면 원래 있던 것도 지움
  • 클래스 바인딩은 클래스 어트리뷰트 보다 우선함
  • 즉, 기존에 마크업된 클래스 어트리뷰트를 리셋, 클래스 바인딩의 내용을 적용

5. 스타일 바인딩

  • [style.css프로퍼티명]=”expression”
  • 인라인 스타일을 만들어줌
  • font-size의 경우 단위까지 기술
  • [style.font-size.em]=”isActive ? 1.2 : 1”

6. 이벤트 바인딩*

  • (event)=”statement”
  • 표현식이 아닌, 구문이 옴
    1
    2
    3
    4
    // 구문에 할당문이 옴
    (click)="isActive=!isActive"
    // $event는 addEventListener의 e객체
    (input)="onInput($event)"

7. 양방향 데이터 바인딩

  • [(ngModel)]=”variable”
  • 사용하기 위해서는 root module에 FormsModule을 추가해야함
  • 양쪽의 단방향을 사용함으로써(프로퍼티, 이벤트바인딩) 양방향인 것처럼 사용 (syntax sugar)
  • 양방향 데이터바인딩은 꼭 필요할 시만 사용 (성능이슈)
  • 사용자 입력과 관련돤 DOM요소에 사용됨 (input, textarea, select.. 폼 컨트롤 요소)
1
2
3
4
5
6
7
8
// import문에 추가he
import { FormsModule } from '@angular/forms';
// 데코레이터의 import문에 추가
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, FormsModule],
providers: [],

Built-in directive

  • 애플리케이션 전역에서 사용할 수 있는 공통 관심사를 분리하여 구현
  • 공통된 관심사를 묶어 HTML 태그의 커스텀 어트리뷰트를 만든다는 개념
    • 컴포넌트는 커스텀 태그를 만든다는 개념

디렉티브 3가지 유형

1. 컴포넌트 디렉티브(Component Directives)

  • 컴포넌트의 템플릿을 표시하기 위한 디렉티브
  • @Component내 seletor 프로퍼티에 임의의 디렉티브의 이름을 정의

2. 어트리뷰트 디렉티브(Attribute Directives)

  • HTML 요소의 어트리뷰트와 같이 사용 (해당 요소의 모양, 동작을 제어)
  • ngClass, ngStyle

3. 구조 디렉티브(Structural Directives)

  • DOM 레이아웃을 변경
  • 구조 디렉티브는 DOM 요소를 반복 생성(ngFor)
  • 조건에 의한 추가 또는 제거(ngIf, ngSwitch)

어트리뷰트 디렉티브

1. ngClass

  • ngClass는 문자열, 배열, 객체, 컴포넌트 메소드에 의한 클래스까지 지원
  • 클래스 바인딩은 문자열에 의한 클래스만을 지원하지만,
  • 즉, css세트를 쓰거나 조건에 의한 클래스 적용시 사용.
  • 복수의 클래스 리스트를 조건(true/false or 함수사용)으로 컨트롤할때 사용

2. ngStyle

  • 인라인 스타일을 만듬

구조 디렉티브

1. ngIf

  • 조건에 따라 요소를 표시할지 말지 (true/false) 결정할때 사용
  • 스타일 바인딩(display:none)으로 하는것은 DOM요소가 남지만, ngIf는 아예 DOM까지 제거
  • false일때의 구문 추가 가능 (else문)
    1
    2
    3
    <div *ngIf="mySkill==='HTML'; else elseBlock">HTML</div>
    <!--else일때 실행할 elseBlock구문-->
    <ng-template #elseBlock><div>CSS</div></ng-template>

2. ngFor

  • 컴포넌트 클래스의 컬렉션을 반복(for문처럼)
  • -> 호스트 요소 및 하위 요소를 DOM에 추가
  • 컬렉션은 일반적으로 배열을 사용
    1
    2
    3
    4
    5
    <!--기본 문법-->
    <element *ngFor="let item of items">...</element>
    <!--옵션 사항-->
    <element *ngFor="let item of items; let i=index; let odd=odd; trackBy: trackById">...</element>

3. ngSwitch

  • js의 switch문과 같은 기능
  • 이전과는 달리 *를 case문에 사용