https://poiemaweb.com/angular-component-data-binding
구조화된 웹어플리케이션을 구축하기 위해서는 뷰와 모델의 분리는 필수적이다. 하지만 뷰와 모델은 유기적으로 동작해야 한다.
이러한 모순점을 해결하는 방식은 여러가지가 있으며 뷰와 모델이 연결된 방식에따라 장단점이 발생한다.

JQuery는 요소노드를 찾아 데이터를 바인딩하는 방식이기때문에 템플릿에서 요소노드의 형식이 변경되면 자바스크립트 코드도 변경이 발생된다는 단점을 가지고 있다.
뷰와 로직이 직접적으로 연결된 방식은 뷰가 변경되면 로직도 변경될 가능성이 매우 높다.
그렇다면 위 단점을 극복하려면 뷰와 로직이 느슨하게 연결되어야 한다.
앵귤러는 DOM에 직접 접근하지 않고 뷰와 모델의 연결됨을 선언하고 내부적으로 프레임워크가 뷰와 모델을 동기화하는 방식(선언형 프로그래밍: Declarative programming)이다.

클래스 데이터와 뷰의 바인딩선언만 하면 되므로 템플릿 요소노드의 형식이 변경되어도 클래스 코드를 변경하지 않아도 된다.
데이터바인딩은 뷰와 모델을 분리할 수 있을 뿐만 아니라 기존의 웹 애플리케이션 개발 방식보다 간결한 코드로 개발이 가능하다.
변화 감지(Change detection)
변화감지란 뷰와 모델의 상태변화를 감지하고 이를 반영하는 것이다.
뷰의 상태변화는 DOM이벤트를 캐치하는 것으로 감지할 수 있지만 모델은 HTML요소노드가 아니므로 이벤트가 발생하지 않는다.
모델의 상태가 변경된다는 것은 클래스 프로퍼티가 변경됨을 의미한다.
앵귤러는 클래스 프로퍼티 값이 변경되는 상황, 즉 어떤 경우 모델이 변화하는지에 주목한다.
일반적으로 모델의 상태가 변하는 경우는 그리 많지 않다.
앵귤러는 후킹로직으로 변화를 감지하고 변화가 감지될 때마다 Digest loop를 실행하여 모델의 변화를 뷰에 반영한다.
데이터 바인딩
인터폴레이션(Interpolation)
<p>{{ contents }}</p>
모델->뷰의 단방향 데이터바인딩으로 {{템플릿표현식}}기호를 사용하며, 여러 템플릿 표현식의 평가결과를 문자열로 변환된 값이 뷰에 반영된다.
프로퍼티 바인딩(Property binding)
모델->뷰의 단방향 데이터바인딩이다.
<element [property]="expression">...</element>
HTML 요소노드, 컴포넌트, 디렉티브의 프로퍼티에 템플릿 표현식 평가결과를 반영한다.
어트리뷰트 바인딩(Attribute binding)
<element [attr.attribute-name]="expression">...</element>
브라우저는 HTML을 파싱할때 HTML요소노드는 DOM 노드객체가 되며 노드객체는 다양한 프로퍼티를 가지게된다.
이때 HTML요소노드의 어트리뷰트는 DOM 노드객체의 attribute프로퍼티로 만들어진다.
<input id="user" type="text" value="ungmo2">
input요소노드는 3개의 어트리뷰트를 가지고있다.
브라우저가 파싱할때 DOM에 HTMLInputElement객체가 만들어지고 3개의 어트리뷰는 노드객체의 attributes프로퍼티로 만들어지고 getAttribute메소드로 접근이 가능하다.
document.getElementById('user').getAttribute('value'); // ungmo2
document.getElementById('user').getAttribute('value') = 'abncd'// 읽기전용이므로 에러발생
DOM노드객체의 attributes프로퍼티중 value프로퍼티만 값이 변하지 않는다. 초기값을 유지한다.
따라서 DOM에있는 input요소노드는 일반 value프로퍼티는 변동가능한 현재의 값을 가지고 있으며 attribue프로퍼티에 있는 value프로퍼티는 변하지 않는 초기값을 가지고 있는 것이다.
클래스 바인딩(Class binding)
클래스바인딩을 사용하면 HTML요소노드의 class어트리뷰트를 설정할 수 있다.
<element [class.class-name]="booleanExpression">...</element>
<element [class]="class-name-list">...</element>
단항클래스바인딩
<div [class.alert]="isError">...</div>
<div class="rounded" [class.alert]="isError">...</div>
<div class="rounded alert">...</div>
<div class="alert" [class.alert]="isError">...</div>
<div class="alert">...</div>
<div>...</div>
다항 클래스 바인딩
<div [class]="my-classes">...</div>
<div class="my-class1 my-class2">...</div>
<div class="my-class1 my-class2" [class]="my-classes">...</div>
my-classes의 값이 ‘my-class3 my-class4’이면
<div class="my-class3 my-class4">...</div>
단항클래스 바인딩은 병합형식으로 적용이되지만 다항클래스 바인딩은 대체방식으로 적용된다.
단항클래스 바인딩은 기존 어트리뷰트보다 우선적용된다.
스타일 바인딩(Style binding)
<element [style.style-property]="expression">...</element>
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<button class="btn"
[style.background-color]="isActive ? '#4CAF50' : '#f44336'"
[style.font-size.em]="isActive ? '1.2' : '1'"
(click)="isActive=!isActive">Toggle</button>
`,
styles: [`
.btn {
background-color: #4CAF50;
border: none;
border-radius: 8px;
color: white;
padding: 10px;
cursor: pointer;
outline: none;
}
`]
})
export class AppComponent {
isActive = false;
}
양방향바인딩
import { FormsModule } from '@angular/forms';
imports: [BrowserModule, FormsModule],
ngModel은 템플릿기반 폼을 위한 디렉티브로 꼭 폼이 사용되지 않더라도 폼컨트롤을 바인딩할때 사용한다.
ngModel디렉티브를 사용하려면 템플릿기반 폼모듈인 FormsModule을 import해야 한다.
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<input type="text" [(ngModel)]="name">
<p>name: {{ name }}</p>
`
})
export class AppComponent {
name = '';
}
[(ngModel)]="name"
양방향바인딩이므로 사용자가 입력하면 입력값이 name프로퍼티값에 반영되고 name값이 변하면 input value프로퍼티값이 변한다.
앵귤러는 양방향바인딩을 내부적으로 단방향바인딩과 이벤트바인딩으로 구분하여 구현한다.
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<input [ngModel]="name" (ngModelChange)="name=$event">
<p>name: {{ name }}</p>
`
})
export class AppComponent {
name = '';
}
ngModel디렉티브는 사용자입력과 관련한 DOM요소(input, textarea, select등의 폼컨트롤 요소)에서만 사용할 수 있다.
< input [ngModel]="name" >
ngModel은 단방향바인딩으로도 사용가능하다.
<input [ngModel]="name" (ngModelChange)="name=$event">
(ngModelChange)="name=$event"은 이벤트를 수신하고 이벤트 핸들러를 통해 DOM의 변화를 외부에 알린다.
ngModelChange는 $event에서 사용자 입력에 관련된 프로퍼티의 값(위 예제의 경우 target.value)을 내부적으로 추출하여 이벤트를 emit한다.