데이터 바인딩의 이해
자바스크립트 웹 애플리케이션의 복잡도가 증가하면서 브라우저의 메모리에 있는 여러 개의 자바스크립트 객체와 화면에 있는 데이터를 일치시키기가 매우 어려워졌다. 이러한 어려운 작업을 쉽게 해주는 해결책이 있다면 그건 데이터 바인딩일 것이다. 데이터 바인딩 이란 두 데이터 혹은 정보의 소스를 모두 일치시키는 기법이다. 즉 화면에 보이는 데이터와 브라우저 메모리에 있는 데이터를 일치시키는 기법이다. 많은 자바스크립트 프레임워크가 이러한 데이터 바인딩 기술을 제공하고 있다. 하지만 대다수의 자바스크립트 프레임워크가 단방향 데이터 바인딩을 지원하는 반면 AngularJS는 양방향 데이터 바인딩을 제공한다.
단방향 데이터 바인딩은 데이터와 템플릿을 결합하여 화면을 생성한다. 반면 양방향 데이터 바인딩을 데이터의 변화를 감지해 템플릿과 결합하여 화면을 갱신하고 화면에서의 입력에 따라 데이터를 갱신한다. 즉, 데이터와 화면 사이의 데이터가 계속해서 일치하게 되는 것이다. Mustache를 이용해 데이터를 바인딩하면 기본적으로 단방향 데이터 바인딩이 이뤄진다. 하지만 대다수 애플리케이션이 사용자의 입력에 따라 데이터를 갱신하고 화면을 업데이트해야 하므로 단방향 데이터 바인딩으로 구성하면 데이터 변화를 감지하고 화면을 업데이트하는 코드를 매번 작성해야 한다.
양방향 데이터 바인딩 예제 코드
<!doctype html>
<html ng-app>
<head>
<meta charset="UTF-8">
<title>Inter way data binding<title>
<script src="../angular/angular.js"></script>
<script>
function mainCtrl ($scope) {
var menuList = [
{itemId: 1, itemName: '센드위치', itemPrice: 2000, itemCount: 0},
{itemId: 2, itemName: '아메리카노', itemPrice: 1000, itemCount: 0},
{itemId: 3, itemName: '카푸치노', itemPrice: 1500, itemCount: 0}
]
$scope.menuList = menuList;
$scope.totalPrice = 0;
$scope.buy = function () {
$scope.totalPrice = 0;
angular.forEach($scope.menuList, function (menu, idx) {
$scope.totalPrice = $scope.totalPrice + (menu.itemPrice * Number(menu.itemCount));
});
};
}
</script>
<head>
<body ng-controller="mainCtrl">
<div>
<h1>메뉴판</h1>
<h2>메뉴 목록</h2>
<table>
<thead>
<tr><th>메뉴</th><<th><가격</th><th>갯수</th></tr>
</thead>
<tbody>
<tr ng-repeat="menu in menuList">
<td></td>
<td></td>
<td><input type="text" ng-model="menu.itemCount"></td>
</tr>
</tbody>
</table>
<button ng-click="buy()">구매</button>
<h2>구입 가격</h2>
<div>
가격:
</div>
</div>
</html>
<body ng-controller="mainCtrl">
ng-controller 지시자를 이용하여 <body> 영역과 연결된 컨트롤러 함수 이름을 지정했다.
<tr ng-repeat="menu in menuList">
메뉴 정보를 테이블의 각 행에 해당하는 <tr> 요소에 출력하고자 한다. 메뉴 정보는 menuList 배열에 보관돼있다. 이러한 경우 ng-repeat 지시자를 이용해 for/in과 같은 형태로 반복적인 데이터를 표현할 수 있다. <tr> 요소를 포함해 내부 요소에서는 menuList에 담겨있는 각 menu에 접근할 수 있다.
<input type="text" ng-model="menu.itemCount"></td>
주문관리 애플리케이션에서 유일하게 사용자의 입력이 들어가는 요소는 <input>
이다. 메뉴의 개수를 사용자가 입력하기 때문이다. 그럼 메뉴의 개수가 메모리상에
데이터로 보관돼야 하고 값이 바뀔 때마다 데이터도 갱신돼야 한다. AngularJS에서는 ng-model을 이용해 자바스크립트 객체와 화면 요소 사이의 양방향
데이터 바인딩을 가능하게 한다. <input>
요소에 ng-model=”menu.itemCount”을 추가함으로써 AngularJS에게 menu 객체의 itemCount 속성을
텍스트 입력 박스의 값과 데이터 바인딩하겠다고 알려준다.
<button ng-click="buy()" class="btn pull-right">구매</button>
ng-click을 이용해 버튼을 클릭할 때마다 “buy()” 표현식을 해석한다. 컨트롤러 함수와 $scope에 할당된 buy 함수를 실행하게 된다.
가격:
컨트롤러 함수에 $scope에 할당된 totalPrice 속성 값을 출력한다. 브라우저 메모리상에 위치하는 localPrice 데이터가 변할 때마다 화면에 표시되는 값도 자동으로 갱신된다.
$scope.menuList = menuList;
$scope 객체에 menuList 속성을 추가한다. 템플릿에서 menuList를 표현식으로 작성했으면 menuList $scope에서 menuList가 속성으로 있는지 찾는다. 있으면 해당 속성의 값을 일겅와 템플릿에서 사용한다. $scope.menuList에 menuList를 대입함으로써 템플릿에서 메뉴 목록 데이터를 접근할 수 있게 했다.
$scope.totalPrice = 0;
$scope의 속성으로 totalPrice를 추가하고 초기 값을 0으로 대입했다.
$scope.buy = function() { ... }
구매 버튼을 클릭할 때 실행되는 함수를 $scope의 buy 속성에 대입했다. 자바스크립트에서는 함수 자체도 하나의 값이므로 속성에 대입하거나 함수의 매개변수로 전달할 수 있다.
$ angular.forEach($scope.menuList, function (menu, idx) {
angular에서 제공하는 forEach 함수다. 첫 번째 인자로는 배열이 오고 두 번째 인자로는 콜백 함수가 온다. 배열을 순환하면서 요소마다 콜백 함수가 실행된다. 실행될 때 콜백 함수의 첫 번째 매개변수로 배열 요소를 전달하고 다음으로 해당 배열 요소의 인덱스를 전달한다.
$ $scope.totalPrice = $scope.totalPrice + (menu.itemPrice * Number(menu.itemCount));
menuList를 순환하면서 각 배열 요소를 menu로 전달하여 위 코드가 menuList 요소 개수만큼 실행된다. 해당 코드는 AngularJS의 양방향 데이터 바인딩
덕분에 가능한 코드다. menu.itemCount가 3번에서 ng-model로 <input>
태그와 바인딩돼 있어 일일이 <input>
태그의 값을 가지고 와서 계산할 필요가
없기 때문이다.
AngularJS의 양방향 데이터 바인딩은 웹 애플리케이션의 복잡도가 증가하면 증가할수록 빛을 발한다. 수많은 코드의 양을 줄여줄 뿐만 아니라 유지보수나 코드를 관리하기 매우 쉽게 해준다. 양방향 데이터 바인딩은 AngularJS의 주요 기능이자 핵심이다.