심화 가이드
템플릿

문자열, 프로퍼티, 어트리뷰트를 동적으로 바인딩하기

바인딩(binding) 은 컴포넌트의 템플릿과 데이터를 연결하는 것을 의미합니다. 템플릿과 데이터를 바인딩하고 나면, 컴포넌트 데이터가 변경되더라도 템플릿에 언제나 최신 정보가 갱신됩니다.

문자열 바인딩

문자열을 바인딩하려면 이중 중괄호({{, }})를 사용하고 괄호 안에 표현식을 작성하면 됩니다.

      
@Component({  template: `    <p>Your color preference is {{ theme }}.</p>  `,  ...})export class AppComponent {  theme = 'dark';}

이렇게 구현하면 Angular는 {{ theme }}dark 로 변환해서 화면에 렌더링합니다.

      
<!-- 렌더링 결과 --><p>Your color preference is dark.</p>

그리고 표현식이 처음 렌더링 된 후에는, Angular가 표현식 값이 변경되는 것을 자동으로 감지하고 화면을 갱신합니다.

만약 사용자가 버튼을 눌러서 theme 프로퍼티의 값이 'light'로 변경되었다면, 이제 화면은 다음과 같이 갱신됩니다:

      
<!-- 렌더링 결과 --><p>Your color preference is light.</p>

HTML에 문자열을 표시하고 싶은 곳이라면 어느 곳에든 문자열 바인딩을 활용할 수 있습니다.

문자열 바인딩 표현식은 모두 문자열 타입으로 변환됩니다. 표현식의 결과가 객체나 배열이라면 toString() 메서드 실행 결과가 사용됩니다.

동적 프로퍼티, 어트리뷰트 바인딩

대괄호([, ])를 사용하면 객체 프로퍼티와 HTML 어트리뷰트를 바인딩 할 수 있습니다.

이 때 프로퍼티는 HTML 엘리먼트의 DOM 인스턴스이거나, 컴포넌트 인스턴스이거나, 디렉티브 인스턴스 일 수 있습니다.

기본 엘리먼트 프로퍼티

HTML 엘리먼트는 DOM 표현과 연결됩니다. 예를 들어 <button> HTML 엘리먼트는 DOM에서 HTMLButtonElement 인스턴스와 대응됩니다. Angular 측면에서 보면, 프로퍼티와 바인딩된 값은 엘리먼트의 DOM 인스턴스와 직접 연결됩니다.

      
<!-- `disabled` 프로퍼티는 버튼 엘리먼트의 DOM 객체와 바인딩 됩니다. --><button [disabled]="isFormValid">Save</button>

이렇게 구현하면 isFormValid 값이 변경될 때마다 Angular가 자동으로 HTMLButtonElement 인스턴스에 있는 disabled 프로퍼티 값을 변경합니다.

컴포넌트와 디렉티브 프로퍼티

바인딩하려는 프로퍼티가 Angular 컴포넌트라면, 대괄호를 사용하는 프로퍼티 바인딩은 컴포넌트의 입력 프로퍼티와 바인딩됩니다.

      
<!-- `MyListbox` 컴포넌트 인스턴스에 있는 `value` 프로퍼티와 바인딩 됩니다. --><my-listbox [value]="mySelection" />

이렇게 구현하면 mySelection 값이 변경될 때마다 Angular가 자동으로 MyListbox 인스턴스의 value 프로퍼티 값을 변경합니다.

디렉티브도 같은 방식으로 바인딩 됩니다.

      
<!-- `NgOptimizedImage` 디렉티브의 `ngSrc` 프로퍼티와 바인딩 됩니다.  --><img [ngSrc]="profilePhotoUrl" alt="The current user's profile photo">

어트리뷰트

ARIA 어트리뷰트나 SVG 어트리뷰트와 같이 연관된 DOM 프로퍼티가 존재하지 않는 경우에는 템플릿 엘리먼트에 attr. 접두사를 붙여서 어트리뷰트와 바인딩 할 수 있습니다.

      
<!-- 컴포넌트의 `listRole` 프로퍼티와 `<ul>` 엘리먼트의 `role` 어트리뷰트를 바인딩합니다. --><ul [attr.role]="listRole">

이렇게 구현하면 listRole 값이 변경될 때마다 Angular가 자동으로 <ul> 엘리먼트의 setAttribute를 실행해서 role 어트리뷰트 값을 변경합니다.

이 때 어트리뷰트에 바인딩되는 값이 null이면, Angular가 removeAttribute를 실행해서 어트리뷰트를 제거합니다.

프로퍼티와 어트리뷰트를 바인딩 할 때 문자열 바인딩

프로퍼티나 어트리뷰트 이름에 대괄호를 사용하는 대신 이중 중괄호를 사용하면 프로퍼티나 어트리뷰트에 문자열 바인딩을 연결할 수 있습니다.

      
<!-- 이미지 엘리먼트의 DOM 객체와 `alt` 프로퍼티를 바인딩합니다. --><img src="profile-photo.jpg" alt="Profile photo of {{ firstName }}" >

어트리뷰트에 문자열 바인딩을 사용하려면 어트리뷰트 이름 앞에 attr. 접두사를 사용하면 됩니다.

      
<button attr.aria-label="Save changes to {{ objectType }}">

CSS 클래스 바인딩, 스타일 프로퍼티 바인딩

Angular는 CSS 클래스 바인딩과 CSS 스타일 프로퍼티 바인딩도 지원합니다.

CSS 클래스

바인딩되는 값이 참인지, 거짓인지에 따라 CSS 클래스를 조건부로 적용할 수 있습니다.

      
<!-- `esExpanded`가 참으로 평가되면 `expanded` CSS 클래스가 추가됩니다. --><ul [class.expanded]="isExpanded">

class 프로퍼티를 직접 바인딩하는 방법도 있습니다. 이 경우 세 가지 타입을 사용할 수 있습니다:

class 값 설명 TypeScript 타입
띄어쓰기로 구분하는 1개 이상의 CSS 클래스 문자열 string
CSS 클래스 문자열의 배열 string[]
프로퍼티 이름을 CSS 클래스 이름으로 하고, 개별 값이 참으로 평가되는지 표현하는 객체 Record<string, any>
      
@Component({  template: `    <ul [class]="listClasses"> ... </ul>    <section [class]="sectionClasses"> ... </section>    <button [class]="buttonClasses"> ... </button>  `,  ...})export class UserProfile {  listClasses = 'full-width outlined';  sectionClasses = ['expandable', 'elevated'];  buttonClasses = {    highlighted: true,    embiggened: false,  };}

위 코드처럼 구현하면 DOM은 다음과 같이 렌더링됩니다:

      
<ul class="full-width outlined"> ... </ul><section class="expandable elevated"> ... </section><button class="highlighted"> ... </button>

유효하지 않은 CSS 클래스 이름은 무시합니다.

정적 CSS 클래스를 사용하거나 class를 직접 바인딩하거나, 특정 클래스를 바인딩하는 경우가 겹치면 Angular는 지능적으로 결과를 조합합니다.

      
@Component({  template: `<ul class="list" [class]="listType" [class.expanded]="isExpanded"> ...`,  ...})export class Listbox {  listType = 'box';  isExpanded = true;}

위 코드처럼 구현하면 Angular는 ul 엘리먼트에 3개의 CSS 클래스를 모두 적용합니다.

      
<ul class="list box expanded">

엘리먼트에 CSS 클래스가 적용되는 순서는 보장하지 않습니다.

class를 바인딩하면서 배열이나 객체를 사용한 경우에는, Angular가 이전 값과 현재 값을 동등 연산자(===)로 비교합니다. 그래서 객체나 배열 내부의 값이 변경되었다면 새 객체와 새 배열을 사용해야 변경사항이 제대로 반영됩니다.

엘리먼트에 같은 CSS가 여러번 바인딩되면, 우선순위에 따라 충돌을 해결합니다.

CSS 스타일 프로퍼티

엘리먼트에 CSS 스타일 프로퍼티를 직접 바인딩 할 수도 있습니다.

      
<!-- `isExpanded` 프로퍼티 값에 따라 CSS `display` 프로퍼티 값을 설정합니다. --><section [style.display]="isExpanded ? 'block' : 'none'">

이 때 단위를 함께 지정할 수 있습니다.

      
<!-- `sectionHeightInPixels` 프로퍼티 값에 따라 CSS `height` 프로퍼티를 픽셀 단위로 설정합니다. --><section [style.height.px]="sectionHeightInPixels">

바인딩 구문 하나에 여러 스타일을 바인딩할 수도 있습니다. 이 경우 세 가지 타입을 사용할 수 있습니다:

style 값 설명 TypeScript 타입
"display: flex; margin: 8px"와 같은 CSS 선언 문자열 string
프로퍼티 이름을 CSS 프로퍼티 이름으로 하고, 개별 값이 해당 CSS 프로퍼티 값인 객체 Record<string, any>
      
@Component({  template: `    <ul [style]="listStyles"> ... </ul>    <section [style]="sectionStyles"> ... </section>  `,  ...})export class UserProfile {  listStyles = 'display: flex; padding: 8px';  sectionStyles = {    border: '1px solid black',    'font-weight': 'bold',  };}

위 코드처럼 구현하면 DOM은 다음과 같이 렌더링됩니다:

      
<ul style="display: flex; padding: 8px"> ... </ul><section style="border: 1px solid black; font-weight: bold"> ... </section>

style에 객체를 바인딩하면 Angular는 이전값과 현재값을 동등 연산자(===)로 비교합니다. 그래서 객체 내부의 값이 변경되었다면 새 객체를 사용해야 변경사항이 제대로 반영됩니다.

엘리먼트에 같은 스타일 프로퍼티가 여러번 바인딩되면, 우선순위에 따라 충돌을 해결합니다.