양방향 바인딩(two way binding) 은 엘리먼트와 어떤 값을 바인딩하면서, 동시에 바인딩한 값이 변경되는 것을 감지하는 방식입니다.
문법
양방향 바인딩 문법은 대괄호를 사용하는 프로퍼티 바인딩과 소괄호를 사용하는 이벤트 바인딩이 조합된 [()]
입니다.
Angular 커뮤니티에서는 비공식적으로 "상자 안에 든 바나나" 라고 하기도 합니다.
폼 컨트롤 양방향 바인딩
양방향 바인딩은 컴포넌트 데이터와 폼 컨트롤을 같은 값으로 동기화하는 용도로 자주 사용됩니다. 사용자가 문자열을 입력하면 컴포넌트의 상태가 갱신되는 과정도 이 경우에 해당됩니다.
아래 코드는 firstName
값을 동적으로 갱신하는 예제 코드입니다:
import { Component } from '@angular/core';import { FormsModule } from '@angular/forms';@Component({ imports: [FormsModule], template: ` <main> <h2>Hello {{ firstName }}!</h2> <input type="text" [(ngModel)]="firstName" /> </main> `})export class AppComponent { firstName = 'Ada';}
기본 폼 컨트롤에 양방향 바인딩을 사용하려면 이렇게 하면 됩니다:
@angular/forms
패키지에서FormsModule
을 로드합니다.ngModel
디렉티브와 양방향 바인딩 문법을 활용해서[(ngModel)]
과 같이 구현합니다.- 갱신할 컴포넌트 프로퍼티를 지정합니다. 위 예제 코드에서는
firstName
과 연결했습니다.
이렇게 한 번 연결하고 나면 <input>
엘리먼트 값이 변경되면 Angular가 변경된 값으로 컴포넌트 상태를 갱신합니다!
NgModel
도 자세하게 알아보세요.
컴포넌트간 양방향 바인딩
폼 엘리먼트가 아니라 부모-자식 컴포넌트에 양방향 바인딩을 연결하려면 설정해야 하는 것이 조금 더 있습니다.
아래 코드는 AppComponent
에서 초기값을 설정하지만 화면을 렌더링하거나 갱신하는 로직은 자식 컴포넌트인 CounterComponent
안에 있는 예제 코드입니다.
// ./app.component.tsimport { Component } from '@angular/core';import { CounterComponent } from './counter/counter.component';@Component({ selector: 'app-root', imports: [CounterComponent], template: ` <main> <h1>Counter: {{ initialCount }}</h1> <app-counter [(count)]="initialCount"></app-counter> </main> `,})export class AppComponent { initialCount = 18;}
// './counter/counter.component.ts';import { Component, model } from '@angular/core';@Component({ selector: 'app-counter', template: ` <button (click)="updateCount(-1)">-</button> <span>{{ count() }}</span> <button (click)="updateCount(+1)">+</button> `,})export class CounterComponent { count = model<number>(0); updateCount(amount: number): void { this.count.update(currentCount => currentCount + amount); }}
양방향 바인딩 연결하기
위 예제에서 보듯이, 컴포넌트끼리 양방향 바인딩하려면 이런 조건이 필요합니다:
자식 컴포넌트에는 model
프로퍼티가 존재해야 합니다.
간단하게 보면 이렇습니다:
// './counter/counter.component.ts';import { Component, model } from '@angular/core';@Component({ // 간략화 한 코드 })export class CounterComponent { count = model<number>(0); updateCount(amount: number): void { this.count.update(currentCount => currentCount + amount); }}
그리고 부모 컴포넌트에는:
- 템플릿에서
model
프로퍼티에 양방향 바인딩 문법으로 바인딩합니다. - 컴포넌트 코드에서
model
프로퍼티의 초기값을 설정합니다.
간단하게 보면 이렇습니다:
// ./app.component.tsimport { Component } from '@angular/core';import { CounterComponent } from './counter/counter.component';@Component({ selector: 'app-root', imports: [CounterComponent], template: ` <main> <app-counter [(count)]="initialCount"></app-counter> </main> `,})export class AppComponent { initialCount = 18;}