2013년 7월 7일 일요일

AngularJS: An Overview (번역)

AngularJS는 복잡한 클라이언트 사이드 애플리케이션 개발을 위해 구글에서 만든 자바스크립트 프레임워크입니다. Angular의 죽여주는 기능은 지시자(directives)로, 자신만의 태그와 속성을 만들어 HTML을 확장할 수 있게 해줍니다. Angular 프로젝트는 여타 다른 자바스크립트 MVC 프로젝트와는 다소 차이가 있지만, 일단 Angular의 구조를 이해하기만 한다면 굉장히 모듈화하기도 쉽고 유지보수하기도 좋습니다. 이제 AngularJS의 주요 컴포넌트와 이들이 어떻게 동작하고 왜 여러분이 Angular를 다음 프로젝트에서 진지하게 고려해봐야 하는지 알아보겠습니다.


AngularJS의 철학


데이터 중심
jQuery 같은 자바스크립트 라이브러리에 익숙한 사람이 AngularJS를 사용하려면 약간의 패러다임의 변화가 필요합니다. AngularJS는 jQuery와 유사해 보이지만 그 반대입니다. 다시 말하면 jQuery는 DOM 조작에 초점이 맞춰져 있어 우리는 DOM을 보고 데이터를 갱신합니다. 반면 Angular에서는 우리가 데이터를 갱신하면 이에 맞춰 DOM을 자동으로 갱신시켜 주는데 이러한 특징 덕분에 결과적으로 개발자의 일이 줄어듭니다.

테스트 용이
AngularJS는 테스트하기 좋게 설계됐습니다. 의존성 주입(Dependency Injection)을 사용하여 많은 객체 중 어느 부분이든 Mock을 생성하기가 편리합니다. 또한 애플리케이션을 개발할 때 기능을 여러 개의 작은 부분으로 나눠서 개발하기 편리하도록 설계되어 테스트가 용이해집니다.

HTML 선언
Angular는 복잡한 웹 애플리케이션을 개발 할 때 HTML을 확장하여 개발에 필요한 언어가 될 수 있도록 설계되었습니다. 또한 자신만의 태그와 속성을 추가할 수 있어 복잡한 작업을 간단한 HTML 태그로 처리할 수 있습니다.

데이터 바인딩

간단한 AngularJS 앱을 살펴보겠습니다. 이  예에서는 두 가지 데이터 바인딩을 사용합니다. 

index.html

1
2
3
4
5
6
<body ng-app>
  <div>
    <input type='text' ng-model='name' />
    <h2>{{name}}</h2>
  </div>
</body>

이 예제에서 어떤 일이 일어나는지 한 줄 한 줄 살펴보겠습니다.
  • <body ng-app>: 모든 Angular 코드는 ng-app 지시자로 감싸야합니다. 이렇게 감싸는 것의 의미는 이 태그 안의 모든 것이 Angular 애플리케이션으로 처리한다는 것을 뜻합니다.
  • <input type="text" ng-model="name"/>: 이 부분은 데이터 바인딩 방법 중 하나입니다. 여기서 사용하는 ng-model 지시자는 input 요소와 바인딩됩니다. (인자(argument)를 갖는 속성 지시자에 대해서도 다룰 겁니다.)
  • <h2>{{name}}</h2>: 우리가 input box에 입력하면 h2 태그는 자동으로 업데이트 됩니다.  바로 이 부분이 제가 전에 언급했던 DOM 자동 변경입니다. 자바스크립트 코드 한 줄 없이도 가능합니다.
모듈
모듈은 AngularJS 애플리케이션의 객체를 구성할 때 사용합니다. 모듈을 애플리케이션의 "코어"로 사용할 수도 있고, 사용되는 모든 클래스를 포함하게 할 수도 있으며, 유사한 기능을 가진 여러 객체를 묶을 때 사용할 수도 있습니다. 이제 예제에서 사용할 모듈을 만들어 보겠습니다.


app.js

1
app = angular.module('myApp', []);


index.html

1
<body ng-app='myApp'>

angular.module의 첫번째 인자로 모듈명을 넣습니다. ng-app에도 같은 이름을 지정하여 모듈에 바인딩되도록 합니다. 두번째 인자는 의존하는 다른 모듈이 있으면 그 모듈의 이름을 배열에 넣습니다. 여기서는 의존하는 모듈이 없으므로 비워둡니다. 지시자와 마찬가지로 AngularJS에서 기본적으로 만들어 둔 모듈을 사용할 수도 있습니다.

이제 모듈을 만들었으니 컨트롤러라 할 수 있는 AngularJS 객체를 처음으로 만들어 보겠습니다. 

컨트롤러

컨트롤러는 특정 HTML 요소와 연결되어 있습니다. 컨트롤러에는 데이터와 함수가 있는데 함수를 통해 컨트롤러는 HTML과 상호작용할 수도 있으며 다른 서비스 객체와 상호작용할 수도 있으며 서버와의 통신을 할 수도 있습니다. 이제 컨트롤러를 만들어 div 와 바인드해보겠습니다.

app.js

1
2
3
app.controller('mainCtrl', function($scope){
  $scope.name = 'Default Name';
});


index.html

1
2
3
4
5
6
<body ng-app='myApp'>
  <div ng-controller='mainCtrl'>
    <input type='text' ng-model='name' />
    <h2>{{name}}</h2>
  </div>
</body>

여기서 우리는 ng-controller 지시자를 사용해 div와 컨트롤러 함수를 연결시켰습니다. 컨트롤러는 기본적으로 $scope라는 인자 한 개를 받습니다. $scope는 html과 상호작용하는 데 필요한 모든 데이터를 갖고 있습니다.  이제 페이지를 새로고침하면 input이 "Default Name"으로 변경된 것을 볼 수 있을 겁니다. 그 이유는 우리가 컨트롤러에 변수를 선언했기 때문입니다.

$scope에 함수를 넣을 수도 있고 HTML에서 함수를 호출하게 할 수도 있습니다. Angular는 다양한 이벤트처리를 위해 여러가지 지시자를 제공합니다. 예제를 수정해 $scope에 함수를 추가하고 ng-click 지시자로 호출하도록 변경해보겠습니다. add 버튼을 추가해 이름을 저장한 뒤 리스트에 보여주도록 하겠습니다.


app.js

1
2
3
4
5
6
7
8
app.controller('mainCtrl', function($scope){
  $scope.name = 'Default Name';
  $scope.people = [];
  $scope.savePerson = function() {
    $scope.people.push[$scope.name];
    $scope.name = '';
  };
});


index.html

1
2
3
4
5
6
7
<body ng-app='myApp'>
  <div ng-controller='mainCtrl'>
    <input type='text' ng-model='name' />
    <button ng-click='savePerson()'>Save Person</button>
    <h2>{{name}}</h2>
  </div>
</body>

이제 사람 목록을 저장할 수 있습니다. 이제 우리가 저장한 사람의 목록을 출력하기 위해 또 다른 지시자인 ng-repeat을 사용해보도록 하겠습니다.


ndex.html

1
2
3
<ul>
  <li ng-repeat='person in people'>{{person}}</li>
</ul>

지금까지 자바스크립트로 데이터를 어떻게 변경하는지를 살펴봤으니 이제는 우리만의 지시자를 생성해서 어떻게 DOM을 변경할 수 있는지를 알아보겠습니다.

지시자(Directives)

이미 예제 애플리케이션에서 여러 개의 지시자를 사용했습니다. 지시자는 우리가 직접 정의할 수도 있는데, 이제 "alertable"이란 지시자를 한 번 만들어보겠습니다. 이 지시자는 HTML 요소를 클릭할 때마다 얼럿 메시지를 보여주는 기능을 합니다.

app.js
1
2
3
4
5
6
7
8
9
10
app.directive('alertable', function(){
  return {
    restrict : 'A',
    link: function(scope, element, attars) {
      element.bind('click', function() {
        alert(attrs.message);
      });
     }
  };
});
그리고 인원 목록에 추가합니다.

index.html

1
2
3
<li ng-repeat='person in people'>
  <span alertable='{{person}}'>{{person}}</span>
</li>
보는 것처럼 예제에서는 지시자를 정의한 객체를 반환합니다. 전달할 수 있는 인자는 여러 개가 있지만 여기서는 예제에서 사용한 두 개의 인자만 살펴보도록 하겠습니다.
  • restrict: 어떤 종류의 지시자인지 명시합니다. 필수로 입력해야하는 값이며 4가지 값이 있습니다.
    • E: 요소. 사용 예: <my-directive></my-directive>
    • A: 속성. 사용 예: <div my-directive></div>
    • C: 클래스. 사용 예: <div class="my-directive"></div>
    • M: 주석. 사용 예: <!-- directive:my-directive -->
  • link: link 함수는 이벤트 리스너를 추가하고 dom을 갱신하는 역할을 맡습니다.
그 외 다른 옵션은 Angular directive documentation에서 확인 할 수 있습니다.

서비스

서비스는 비지니스 로직이 있거나 데이터를 처리하는 클래스입니다. 이제 이전 예제를 리팩토링해서 사람 목록 데이터를 처리하는 서비스를 만들어 보겠습니다.


app.js

1
2
3
4
5
6
7
8
app.factory('PersonService', function() {
  var PersonService = {};
  PersonService.people = [];
  PersonService.addPerson = function(person) {
    PersonService.people.push(person);
  };
  return PersonService;
});
보는 것처럼 서비스는 컨트롤러와는 만드는 방법이 상당히 다릅니다. 컨트롤러는 단순히 함수였다면 서비스는 객체를 반환하는 함수입니다. 이 말은 원한다면 서비스에 private 메서드를 추가할 수도 있다는 의미입니다.

이제 이렇게 만든 서비스에 컨트롤러가 접근하도록 해야합니다. 이 둘은 같은 모듈에 있어 설정하기 쉬운데 이는 Angular의 마법과 같은 특징 중 하나입니다. 컨트롤러가 서비스에 접근하려면 다음처럼 서비스로 넘기면 됩니다.
1
app.controller('mainCtrl', function($scope, PersonService){});
정말로 놀라운 점은 컨트롤러 함수에서 인자의 순서를 변경해도 함수 동작에 변함이 없습니다. 즉 다음처럼 입력한다는 것입니다.
1
app.controller('mainCtrl', function(PersonService, $scope){});
이렇게 해도 함수는 완벽하게 똑같이 동작하는데 그 이유는 AngularJS는 인자의 이름을 보고 무엇을 넘길지 결정하기 때문입니다. 그렇다면 자바스크립트 코드를 minify하면 문제가 되지 않을까 걱정하실텐데요. 정확한 지적입니다. 하지만 다행히도 Angular는 코드를 minify한 후에도 문제가 발생하지 않도록 또 다른 함수 선언 방법을 제공합니다. 문자열 배열을 인자로 넘겨 인자가 무엇인지 angular에게 알려주게 하는 방법입니다. 실제 함수는 배열의 마지막에 위치시킵니다. 그러면 컨트롤러는 다음과 같은 모습일겁니다.
1
app.controller('mainCtrl', ['$scope', 'PersonService', function($scope, PersonService){}]);
Angular는 서비스를 개발할 때 서버와 통신하는 데 필요한 유용한 모듈을 제공합니다. 가장 유용한 모듈은 ngHttp와 ngResource입니다. ngHttp는 HTTP request를 생성할 때 사용하는 모듈이고 ngResource는 ngHttp를 확장시켜 REST API를 지원하게 만들어주는 모듈입니다. 이 두 모듈을 보면 왜, 언제 서비스를 선언해야 하는가를 알 수 있는데 객체를 반환하는 함수를 만들어야 한다면 ngResource처럼 객체를 확장시켜 반환하는 함수를 사용합니다.

Routing
Angular는 URL 라우팅을 지원합니다. 모둘의 config 함수를 사용해 라우팅을 설정할 수 있습니다. 예제 페인 페이지의 구조를 분리시켜 인원 목록의 사람마다 프로필 페이지를 만들 수 있습니다. 다음 예제처럼 설정하면 됩니다.

app.js

1
2
3
4
5
6
7
8
9
10
app.config(function($routeProvider){
  $routeProvider.when('/', {
    templateUrl: 'templates/home.html',
    controller: 'homePageCtrl'
  });
  $routeProvider.when('/person/:id', {
    templateUrl: 'templates/profile.html',
    controller: 'profileCtrl'
  });
});

필터
필터는 작지만 AngularJS에서 종종 유용하게 사용됩니다. 필터는 데이터는 변환시켜 사용자에게 보여줄 때 사용합니다. 지시자처럼 직접 만들 수도 있고 Angular에서 제공하는 필터도 있습니다. 다음 HTML을 살펴보도록 하겠습니다.


1
<span>Price:</span> 300

브라우저는 다음처럼 출력합니다.


1
Price: 300

여기에 필터 두 개를 "|" 연산자를 이용해서 출력을 다르게 바꿔보겠습니다.


1
<span>{{ "Price:" | uppercase }}</span> {{ "300" | currency }}

그러면 출력은 다음처럼 됩니다.


1
PRICE: $300.00


앞으로 더 읽으면 좋은 것들

이 글이 여러분들에게 도움되었길 바라지만 지금까지 다룬 내용은 Angular.js로 무엇을 할 수 있는지 겉핡기 정도로만 다뤘습니다. Angular에 대해 조금 더 알고 싶다면 다음의 자료가 도움이 되리라 생각합니다.




원본 링크: http://glennstovall.com/blog/2013/06/27/angularjs-an-overview/?utm_source=javascriptweekly&utm_medium=email


댓글 없음: