모바일/Javascript

[AngularJS] Two-way Data Binding

박종명 2016. 7. 10. 18:44
728x90

처음 AngularJS를 접했을 때 가장 눈에 띄는 특징이 바로 양방향 데이터 바인딩(Two-way Data Binding)이었다.

개인적으로, 자동 바인딩의 참신함은 knockout.js에서 그 놀라움을 처음 발견하였는데, 어느덧 더욱 발전된 형태의 양방향 자동바인딩을 AngularJS에서 어여쁘게 제공하고 있지 않은가...

이는 단연 AngularJS의 가장 큰 장점이며, 이 프레임워크를 채택하는데 있어, 가장 주요한 기준일 것이다.

AngularJS의 양방향 바인딩은, 응용프로그램의 '모델'과 이를 표시하는 '뷰'간의 자동 동기화를 지원하는 기능이다. 조금 다른 측면에서 설명하자만 자바스크립트 영역과 HTML 영역간의 데이터 동기화를 지원하는 것이다.

AngularJS 공식 사이트에서는 다른 전형적인 자바스크립트 템플릿 시스템과 AngularJS의 바인딩을 다음과 같이 그림으로 비교하고 있다.

Data Binding in Classical Template Systems

- 여타 프레임워크는 단방향 바인딩만 지원
- 동기화를 위한 추가코딩 필요

 Data Binding in Angular Templates

- AngularJS는 양방향 바인딩으로 동작
- 뷰와 모델간 동기화가 자동으로 유지됨

가장 보편적으로 사용되는 jQuery의 경우를 보면,
jQuery 탐색 기능을 사용하여 DOM에서 특정 HTML요소를 찾아내어 이벤트를 리스닝하고, DOM요소의 값을 파싱해서 이 값을 가지고 필요한 작업을 수행하고 했다.
AngularJS에서는 단순히 자바스크립트 속성을 정의하고 이것을 HTML에 바인딩만 하면 된다. 그것으로 끝이다.(by AngularJS in Action)

jQuery의 DOM 탐색, 이벤트 리스닝, 수동 동기화 코드로 가능한 바인딩 작업을 AngularJS에서는 극도로 단순화 시킨 것이다.

* 자동 데이터 바인딩

자동 데이터 바인딩을 위한 아주 간단한 코드를 한번 살펴보자

<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>

<div ng-app="">
    <p>Input something in the input box:</p>
   <p>Name : <input type="text" ng-model="name" placeholder="Enter name here"></p>
   <h1>Hello {{name}} </h1>
</div>

</body>
</html>

모델과 뷰의 동기화를 위해 필요한 작업이 이것이 전부이다.
- ng-app 선언: 해당 영역이 AngularJS 응용프로그램으로 동작하도록 선언한다. 여기서는 모듈의 이름을 생략했는데, 실제 규모있는 앱을 제작하는 경우에는 적절한 이름을 지정하는 것을 권장한다.

- ng-model 지정: 모델로 사용할 값을 지정하는 것으로, 여기서는 input 박스에 name이라는 이름으로 모델을 지정했다. ng-model 디렉티브는 모델로부터 뷰로 데이터를 바인딩 시키기 위해 사용하며 이렇게 하면 AngularJS는 자동으로 $scope 객체의 속성으로 추가되어 뷰와 상호작용이 가능해진다.

- {{ }} 표현식: 모델로 지정한 값을 HTML로 바인딩하기 위한 표현식을 기술한다. 모델값이 변경되면 HTML에 표시된 값이 자동으로 즉각 반영될 것이다.

결과화면은 다음과 같댜. input박스의 값을 변경시키면 그 즉시 HTML에 표시된 값도 같이 변경된다.

 

* 양방향 (자동) 데이터 바인딩

그럼 이제, 좀더 일반적인 형태의 AngularJS 예제를 보자.
아래 코드는, AngularJS에 컨트롤러를 정의하고 이 컨트롤러를 통해 모델 정보에 접근하도록 했다.
이것이 보편적인 AngularJS 코딩 방법이다.

<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function() {
    main = this;
    main.name= "mkex";
//모델로 사용될 정보. HTML영역에 바인딩되어 자동 동기화 됨
   
    //자바스크립트 영역의 값의 변화를 보기 위한 메서드
    main.getName = function(){
      return alert(main.name);
    }
});
</script>
<body>
  <div ng-app="myApp" ng-controller="myCtrl as main">
    Name: <input ng-model="main.name">
    <h1>{{main.name}}</h1>
    <button ng-click='main.getName()'>check</button>
  </div>
</body>
</html>

input 박스의 데이터 변화는 HTML에 바인딩 된 값 뿐만 아니라, 자바스크립트 영역에 정의된 컨트롤러의 main.name 속성의 값도 자동으로 반영된다. 이것이 양방향 자동 바인딩 인 것이다.
(데이터 바인딩은 사용자가 속성값을 직접 조작할 수 있는 HTML 폼 같은 특별한 경우에는 양방향으로 동작한다 - by AngularJS in Action)

결과화면은 다음과 같다.

 

이 얼마나 극강의 생산성을 보여주는 기능인가? 자바스크립트 영역에 정의된 각종 데이터와 이 데이터를 투영하는 HTML요소의 자동 바인딩은 웹 응용프로그램의 무한한 가능성을 쉽게 시도할 수 있도록 할 것이다. 자바스크립트 객체만 잘 관리하면 HTML에 표시되는 것은 신경쓰지 않아도 되며 반대로 HTML로 부터 발생한 변경사항 역시 자바스크립트 객체로 바로 반영될 수 있어 SPA 실현은 쉬운 죽 먹기가 될 수 있다는 것이다. 놀라웁다~

* 단방향 데이터 바인딩(One-way Data Binding)
- 항상 그렇듯이, 훌륭한 기능도 필요치 않을 때가 종종 생긴다. AngularJS의 자동 양방향 데이터 바인딩은 진정 휼륭하지만, 어떤 경우에는 이 기능이 오버스펙일 경우가 있다.
또한 양방향 데이터 바인딩은 내부적으로 변경사항을 감시하는 메커니짐을 내포하고 있어 오버헤드가 생길 수 밖에 없다. (세상에 공짜는 없다)

이에, AngularJS 1.3부터는 one-time binding 이라는 일회성 바인딩 기능을 제공한다.
일회성 바인딩을 적용하기 위해 필요한 것은 단지, '더블클론(::)'의 지정 뿐이다.

이전의 예제에서 단방향 데이터 바인딩으로 변경해 보자.
아래 코드를 보면, 바뀐 것이라곤 고작 두 개의 콜론을 추가한 것 뿐이다. 이로써 최초 한번만 바인딩 되고 이후 변경사항은 HTML로 전파되지 않는다.

<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function() {
    main = this;
    main.name= "mkex";
  
    main.getName = function(){
      return alert(main.name);
    }
});
</script>
<body>
  <div ng-app="myApp" ng-controller="myCtrl as main">
    Name: <input ng-model="::main.name">
    <h1>{{::main.name}}</h1>
    <button ng-click='main.getName()'>check</button>
  </div>
</body>
</html>

결과를 보면 더욱 명확하다.
최초 mkex라는 자바스크립트 영역의 속성 값이 HTML요소로 동기화 되었으며 이후 input 박스의 변화는 더 이상 HTML요소로 동기화 되지 않는다. 
다만 alert 창을 보면 input 박스의 변경은 자바스크립트 속성의 변화만 일으킨다.