read

Angular JS 입문 2


phone

이전 포스팅에 이어 Angular 공부를 계속 해볼까 한다.

이번에는 앵귤러의 핵심 윈리에 대해 알아 볼 것이고, 특히 지시자 (directive)에 대해 중심적으로 알아보도록 하자.


Angular 지시자


그럼 먼저 지시자는 무엇일까??

공식 문서를 한번 보자

고수준에서 지시자는 앵귤러의 HTML 컴파일러($compile) 에 지시할 목적으로 DOM엘리먼트 (속성, 엘리먼트 이름, 주석, css 클래스와 같은)에 붙이는 표식이다. DOM엘리먼트에 특정 동작 방식을 바인딩하거나 심지어 DOM 엘리먼트와 자식들을 변환하기 위해 사용된다.

즉, 지시자는 앵귤러가 해석해서 HTML의 기본 동작 방식을 확장할 목적으로 만든 추가 마크업이다.

지시자는 사용자 정의 HTML 엘리먼트, 속성, 클래스, 주석으로 명시할 수 있다. 예를 들어 보자.

<ng-foo>여기는 엘리먼트로 사용된다</ng-foo>

<div ng-foo="여기는 속성으로 사용된다."></div>

<div class="ng-foo">여기는 클래스로 사용된다.</div>

<!--여기서는 주석으로 사용된다.-->
<!-- directive:ng-foo-->

그럼 이 예제에서 몇가지 집고 가자.

먼저 지시자는 엘리먼트, 속성, 클래스, 주석으로 사용될 수 있다. 하지만 실제로는 모든 지시자가 이런 식으로 사용될 수는 없다. 예를 들어 컬렉션에서 항목을 순회하기 위해 사용되는 ngRepeat 지시자는 속성으로만 사용할 수 있다. 이 주제는 뒤에 자세히 예기할 것이다.

또한 기존 앱을 지원하기 위해 이미 존재하는 클래스와 주석은 피하고 엘리먼트와 속성으로만 지시자를 사용하는 방식이 우수 관례라는 것도 알고 가자.

위 예제에서 또 볼 것은 HTML이 ngFoo를 참조하는 방식이다. 관례상 앵귤러 지시자는 camel 표기법으로 작명한다.

하지만 HTML에서 사용될 때 지시자는 모두 소문자로 바뀌며 단어를 구분하기 위해 ‘-‘가 들어간다. 앵귤러가 HTML에 내장된 지시자를 처리할 때는 다음 단계를 밟아 정규화한다.

1. 이름에서 x- 와 data-를 제거한다.

2. :, -, _로 구분된 이름을 낙타등 표기법으로 변환한다.

이는 HTML에서 ngRepeat가 ng-repeat, x-ng-repeat, data-ng-re-peat, ng:repeat, ng_repeat로 쓰일 수 있음을 의미한다.

물론 대시를 쓰는 경우를 선호한다.

중요한 것은 앵귤러가 공식지시자의 접두어로 ng를 사용하므로 조심하도록 하자. 또한 HTML5에서 ng가 제대로 먹히지 않을 수 있으니 data-ng를 권장한다.


지시자를 사용하는 예제


그럼 일반적인 지시자를 포함하는 앵귤러 앱을 살펴보자.

<!doctype html>
<html ng-app="app">
	<head>
		<meta charset="utf-8">
		<title>Angular Directives</title>
	</head>
	<body ng-controller="ExampleCtrl">
    	<div ng-repeat="person in people">
    	 
    	</div>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
      <script type="text/javascript">
      'use strict';
      var app = angular.module('app',[]);

      app.controller('ExampleCtrl',['$scope', function($scope){
      	$scope.people = [
      	{
      		firstName : 'Colin',
      		lastName : 'Ihrig'
      	},
      	{
      		firstName : 'Adam',
      		lastName : 'Bretz'
      	}
      	]
      }]);
      </script>
	</body>
	</html>

이전과 비슷하지만 더 쉬운 예제다.

ng-app으로 html 엘리먼트에 붙어있는 ngApp을 살펴보자.

ngApp은 새로운 앵귤러 앱을 생성하기 위해 사용되며 앱의 최상위 엘리먼트에 붙여야 한다. ngApp은 HTML 문서당 하나만 사용될 수 있다. 여기서는 app으로 명명했다.

그리고 또 다른 지시자는 ngController다. 이미 설명했듯이 앵귤러는 앱 설계를 위해 MVC 접근 방식을 지원한다. 이 ngController는 앱의 특정부분을 위해 컨트롤러를 명시하도록 도와준다.

여기서는 ExampleCtrl이라는 컨트롤러를 body 엘리먼트에 붙였다. ExampleCtrl의 기능은 예제의 하단 부분에 존재하는 자바스크립트에 나온다. 이 컨트롤러는 (컨트롤러 코드에서 $scope로 참조되는) 모델에 people이라는 변수를 추가할 뿐이다.

마지막 지시자는 ngRepeat이다. ngRepeat는 컬렉션의 엘리먼트를 순회하기 위해 사용한다. 여기서는 people에 속한 모든 엘리먼트를 각각 person이라는 변수로 루프 순회한다.


지시자 생성


앵귤러는 꾀 유용한 내장 지시자가 있지만 아마 필연적으로 기본 기능을 확장해야겠다라는 생각이 들 것이다. 여기서 앵귤러는 굉장히 편리한 API를 제공한다.

지시자는 directive() 함수를 사용해서 개별 모듈에 등록된다. directive()는 파라미터 2개를 받는다. 첫번째는 정규화된 지시자 이름(my-directive 대신 myDirective)이다. 두번째는 앵귤러의 HTML 컴파일러인 $compile에 지시자가 어떻게 동작해야 하는지 알려주는 객체를 반환하는 팩토리 함수다.

팩토리 함수 인자가 반환한 객체는 지시자 정의 객체로 알려져 있으며 속성으로 지시자의 동작방식을 정의하는 평범한 자바스크립트 객체다.

priority, scope, controller, transclude, compile, link, terminal, template, templateUrl, restrict

가 있으며 이에 대한 설명은 이곳을 참조하자.

예시를 들어 보겠다.

<!doctype html>
<html ng-app="app">
	<head>
		<meta charset="utf-8">
		<title>Angular Directives</title>
	</head>
	<body>
    <author-names></author-names>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
    <script type="text/javascript">
    'use strict';
    var app = angular.module('app',[]);

    app.directive('authorNames',function($compile){
    	return {
    		restrict : 'E',
    		controller : function($scope){
    			$scope.people = [
						{
							firstName : 'Colin',
							lastName : 'Ihrig'
						},
						{
							firstName : 'Adam',
							lastName : 'Bretz'
						}
    			];
    		},
    		link : function(scope,element,attrs,controller,transclude){
    			var template =scope.people.map(function(person){
    				var str = '<div>' + person.firstName + ' ' + person.lastName + '</div>';
    				return str;
    			}).join('');
    			var newElement = $compile(template)(scope);

    			element.replaceWith(newElement);
    		}
    	}
    })
    </script>
	</body>
	</html>

여기까지 내장 지시자의 동작과 독자적인 지시자를 어떻게 생성하는지 알아보았다. 딱히 내장지시자를 설명하지도 않았고, 지시자 정의 객체에 설정가능한 모든 옵션을 소개하지도 않았다. 집중한 것은 지시자 개발의 핵심사항이고 앵귤러 문서를 읽기에 크게 어려움이 없을 만큼 알 수 있게 될 것이다.

사실 나도 처음 봤을 때 생각보다 복잡하구나 라는 생각을 했다. 보통 Angular는 쉽다고들 하는데 왜 시작부터 이렇게 복잡할까 생각할 수 있다. 쉽게 배우려면 쉽게 배울수 있다. 분명 그게 더 접근이 쉬울 것이다. 그치만 일단 책의 커리큘럼을 따라가 보기로 한다. 이해한 후 쉬운것을 보면 그 내부적인 것도 볼 수 있을 것이라 생각한다. 혹시나 좀 힘들다면 조금 쉬운 설명이 되어있는 블로그를 찾아봤는데 위에 링크 걸었던 이곳에서 한번 쭉 읽고 오는 것도 도움 될 듯 하다.


컨트롤러


phone

간단하게 정리해보자.

AngularJS는 ng-directives HTML의 확장이다.

ng-app directive는 AngularJS 어플리케이션을 정의한다.

ng-model directive는 어플리케이션 데이터를 제어(input, select, textarea)하는 HTML 값을 연결한다.

ng-bind directive는 어플리케이션 데이터를 HTML 뷰에 연결한다.

이렇게 하면 좀 쉽게 정리 될 것이다.

우리는 이전까지 지시자, directive에 대해 알아보았다. 단순히 내장된 것들을 사용하는 게 아니라 직접 만들어서 사용할 수도 있게 되었다.

그리고 이제 컨트롤러에 대해 알아보도록 하자.

컨트롤러는 코드 재사용성과 테스트 용이성을 높이는 프레임워크를 생성한다. 컨트롤러는 앵귤러 앱의 기본 구성 요소다.

앵귤러와 관련된 다른 모든 것과 마찬가지로 컨트롤러는 자바스크립트 함수일 뿐이라는 사실을 기억해야 한다.

이런 함수는 새로운 앵귤러(또는 스코프) 콘텍스트를 생성하기 위해 사용되며 HTML 마크업에 바인딩된다.

컨트롤러는 특정 HTML 태그 집합에 밀접한 앱과 뷰 논리를 담을 장소를 제공한다. 단일 뷰가 여러 컨트롤러를 사용할 수 있다는 사실을 명심하자. 뷰에서 컨트롤러로 가는 관계는 1대1이 아니다. 또한 여러 뷰에서 컨트롤러를 재사용할 수 있다.


구문


그럼 앵귤러 컨트롤러를 정의하기 위해 사용된 구체적인 구문을 살펴보자.

var app = angular.module('app',[]);
app.controller('main', ['$scope', '$http', function($scope, $http){
//...
}]);

먼저 첫 행은 앵귤러 모듈을 생성한다. 모듈은 앱 내에서 논리적인 단위를 표현한다.

컨트롤러, 서비스, 필터, 지시자 하나 이상이 모듈 내부에 패키지로 묶여 있다.

여기서는 app이라는 새로운 모듈을 생성한다. 이 app은 모든 컨트롤러가 위치할 전체 앵귤러 앱으로 생각하자. 함수 서식을 보면 모듈 이름 뒤에 의존성을 담은 문자열 배열이 따라온다.

의존성현재 모듈이 올바르게 동작하는 데 필요한 또 다른 모듈에 대한 참조다.

앵귤러는 app모듈을 생성하기 전에 의존성 목록에 열거된 모든 모듈이 올라오도록 한다. 여기서는 크게 하지 않지만 추후에 사용해 볼 것이다.

app.controller는 컨트롤러 객체를 앱에 추가할 수 있게 한다. module() 함수와 유사하게 파라미터를 보면, 첫번째는 컨트롤러 이름, 두번째는 의존성 목록, 세번째는 함수다. 함수는 주 컨트롤러를 위한 논리가 들어갈 장소다.

의존성 목록에서 첫 두 항목은 이 컨트롤러가 요구하는 $scope, $http다. $scope는 모든 컨트롤러가 가지고 있는 지역 스코프 콘텍스트며 $http는 앵귤러 HTTP 모듈이며 원격 자원을 위한 HTTP 요청에 사용된다.

함수 서식은 컨트롤러 함수 내부에서 $scope와 $http 변수에 접근할 수 있다는 사실을 알려준다. main 컨트롤러를 생성할 시점에서 앵귤러는 새로운 $scope 객체와 $http 객체로 이 함수를 수행할 것이다. 이 컨트롤러 함수에 의존성으로 열거되었기 때문이다.

컨트롤러를 선언하고 앵귤러로 의존성을 명시하는 다른 방법도 있지만, 위 예시와 같은 접근 방법을 선호하는 이유는 코드가 최소화된 다음에도 계속해서 동작할 것이기 때문이다. (즉, 컴프레셔를 말한다.)

위 예시에서는 배열을 사용해서 어노테이션을 배열로 넘기는 방법으로 이 컨트롤러에 필요한 의존성이 무엇인지 명시적으로 알려줬다.

앵귤러는 이름을 사용해도 의존성을 추론 할 수 있지만, 코드가 최소화된 다음에는 동작이 실패할 것이다. 최소화 될 시 대부분 변수는 한글자로 줄어드므로 그렇게 된다.

이후에 의존성에 대해 좀더 알아보는 것은 다음 포스팅으로 넘기도록 하겠다

Blog Logo

구찌


Published

Image

구찌의 나도한번 해블로그

구찌의 개발 블로그 입니다.

Back to Overview