read

Angular JS 시작하기


computer

이번에 새로운 작업을 하나 맡게 되면서, 어떤 기술을 사용하는 것이 좋을까? 서칭을 한 결과 빠르고 간단히, 효율적으로 만들 수 있는 방법으로 iOnic 을 선택하게 되었다.

물론 여러가지 방법이 있겟지만 지난 프로젝트로 javascript, phonegap, jQuery를 사용하면서 기초를 다졌고 (사실 처음부터 AngularJS를 사용할 수 있었지만 좀더 기본적인 것을 원했다.) 이제는 Angular를 배우면서 편의까지 따져도 되겠다라고 판단했다.

그래서 Angular를 무엇으로 공부할까 고민했는데 물론 좋은 기초책과 함께 보면 좋겠지만 본업은 학생인지라 돈도 그리 많지 않고, 이전에 사놨던 풀스택 개발자를 위한 MEAN 스택 입문이라는 책과 (책 제목이 그리 마음에 들지는 않지만 내용은 알찰 것이라 기대한다. 영문판 번역본이기에…) w3school에 무료 튜토리얼도 있고, 또 codeacademy에 가면 Angular 강의도 올라와 있었다. (react도 올라와 있어서 추후에 봐야겠다.)

실제 Angular.org에 들어가보면, code School에서 제공하는 무료 튜토리얼과 연결해 두었으니, 이곳도 좋은 듯하다.

지금은 Angular 2.0이 나왔고 이전 Angular 1.x 보다 더욱 좋은 모습으로 변했다. 그러나 튜토리얼 상황상 2.0이 올라온 곳은 code School밖에 없어 먼저 자료가 많은 1을 공부하고 code school에서 2를 공부하는 방향으로 생각하고 있다.

내가 봤을 때는 굳이 책을 사지 않아도 공부할 수 있는 사이트가 굉장히 많을 것이라 생각한다. 책이 유일한 한글도서라 모르는 게 나오면 참고 정도로 하고 codeacademy를 기본으로 하고 한번 정리해서 적어보도록 하겠다.


AngularJS란?


그럼 시작부터 함께 해보자. AngularJS를 우리는 정말 자주 접하게 되었다.

간단하게 말하면 프런트앤드 프레임워크이고 단일 페이지 앱(SPA)을 생성하기 위해 사용된다. 또한 오픈소스이고 자유롭게 사용할 수 있다.

기본적으로 javascript, html, css는 알고 있어야 한다. 물론 프런트앤드라 DB나 서버쪽은 조금 몰라도 상관 없다.

TDD나 BDD도 알고 있다면 큰 도움이 될 것이다.

무엇보다 Angular를 사용하는 큰 이유는 쉽게 배울 수 있다는 것이다.

거기에 따라오는 단점이라 하면 깊이를 모른다는 점인데, 개인적으로는 이 점 때문에 javascript부터 제대로 배우는 것을 택했다.

codeacademy의 장점은 코딩부터 시작한다. 계속 쳐보며 익숙해지기를 원하는 데 code school(사실 여기서 공부해 보는 것은 처음이다.)은 영상강의까지 있다. 영어로 말하긴 하지만 충분히 이해할 수 있는 범위다. 또한 w3school은 읽기 전용인 것 같아 조금 아쉽긴 하다.


MVC


Angular는 모델-뷰-컨트롤러(Model-View-Controller)아키텍처를 프런트엔드 웹 앱에 도입했다. MVC 접근 방법을 따를 경우 사용자 인터페이스와 독립적으로, 모델은 데이터층에서 앱을 정의한다.

Angular에서 모델은 평범한 자바스크립트 객체처럼 단순하다. 는 모델 데이터의 시각적인 표현이다. Angular는 뷰 생성을 위한 템플릿 언어로서 Directive(지시자)로 알려진 확장과 더불어 HTML을 사용하게 허용한다. 컨트롤러 구성요소는 모델의 데이터를 조작할 책임을 맡는다. 앵귤러 앱에서 컨트롤러는 controller() 함수를 사용하여 앱에 등록한 자바스크립트 함수이다.

쉽게 보면 사용자가 컨트롤러를 사용하면 컨트롤러가 모델을 조작하고 모델이 뷰를 갱신해서 뷰는 사용자에게 보여주는 프로세스가 MVC이다.

앵귤러의 가장 잘 알려진 기능이 바로 모델과 뷰 사이의 양방향 바인딩인데, 데이터 동기화가 된다는 것이다. 만약 사용자가 뷰를 갱신하면 모델 데이터도 자동으로 갱신되어 변경사항을 반영한다는 의미다.

무슨 말인지 몰라도 아직 큰 상관없다. 아마 마지막에 한번 다시 읽으면 쭉 이해 되리라 생각한다. 하나씩 천천히 알아가도록 하자.


알아가기


Directive(지시자)는 HTML 태그로 사용되는데, 어떠한 javascript코드를 실행할 수 있도록, Angular에게 말해주는 역할을 한다.

Module(모듈)은 Angular application을 만들 때, 우리의 코드를 유지가능하게, 테스트 가능하게, 읽을 수 있게 만든다. 또한 우리의 app의 dependency를 정의할 수 있게 한다. 예를 들면 또다른 모듈들을 dependency로 정할 수 있다.

그럼 module을 만들어보자.

var app = angular.module('store', []);

물론 지금 당장 이 코드를 자바스크립트에 선언한다고 해서 바뀌는 것은 없다. 아직 라이브러리 등록이라던지 HTML 태그에서의 선언도 배우지 않았다.

단순히 저 문장을 해석해 보자.

angular는 angularJS를 의미하고, store은 Application name이다. 또한 뒤의 []는 dependency를 의미한다.

그럼 이제는 사용할 수 있게 만들어 보자.

angular.html

<!DOCTYPE html>
<html ng-app="store">
	<head>
		<meta charset="utf-8">
		<title>Angular Tutorial</title>
	</head>
	<body>
		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
		<script type="text/javascript" src="app.js"></script>
	</body>
</html>
app.js

var app = angular.module('store',[]);

위 예제는 html과 js파일 두가지 이다.

한가지 일반적이지 않다고 느끼는 것은 html 태그로 선언되어 있는 ng-app="store" 부분일 것이다.

ng라고 들어가 있는 것은 앵귤러 앱에서 쓰는 접두어로 보면 된다.

즉, app.js에서 선언한 모듈이 실행 될 때, ng-app에 선언되어 있는 이름과 매치가 되어 실행할 부분을 선언하는 것이다. 다시 말하면 document가 load될 때에 이 부분을 실행 하겠다는 것이다.

여기서 ng-app을 앞서 말한 directive라고 부른다. AngularJS에서는 body element에서 해당 모듈이 있다는 뜻이고, application's scope라는 단어로 쓰인다.

이부분에 있어서 위에서 설명한 directive같은 경우는 아마 다음 포스팅에서 좀더 구체적으로 다룰 것이다. 그리고 방금말한 application’s scope의 경우 잠시 후에 좀 더 보충이 될 것이다.

책에서의 내용은 상당히 초보자가 보면 멍할 수도 있다고 생각이 드는데, 그래도 내용이 정말 알차다. 진도도 대부분 기초는 안다고 하고 가기 때문에 하나하나 놓치지 않고 읽어간다면 이해할 수 있을 것이다.

위에 나온 예제는 code school에서의 예제 였고, 책에 나온 Hello World 출력문을 보도록 하겠다.

angular.html

<!DOCTYPE html>
<html lang="en" ng-app="app" class="no-js">
	<head>
		<meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
		<title>Data Binding Example</title>
	</head>
	<body>
    	<input ng-model="example"/>
        <div></div>
		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
		<script type="text/javascript">
        	var app = angular.module('app',[]);
        </script>
	</body>
</html>

여기는 따로 js파일을 주지 않고 한 페이지에서 다 넣어주었다. 아직 배우지 않은 내용도 많지만, 한번 접해두라는 의미이고 무엇보다 책은 데이터 바인딩에 대해 강조를 하고 있다. 그것이 앵귤러를 사용함에 있어서의 큰 의미이고 효율성이기 때문이다.

앞으로 하나하나 설명할 것이니 너무 당황하지 않아도 된다. codeacademy에서는 지금보다 더한 상황을 바로 코딩을 하기 떄문에 천천히 가자라는 생각으로 하면 더욱 도움될 것이다. (물론 뒤에 설명도 해준다.) 앞에서 말한 내용도 이렇게 간단히 하고 넘어가진 않으니 익힌다는 마음으로 보면 좋을 듯 하다.

한가지 예제를 더 보여줄 것인데, 이 역시 안배운 내용이 많으니 천천히 보도록 한다. 다만 양방향 데이터 바인딩에 대한 내용을 잘 알아두면 얼마나 많은 기능이 쉽게 서술 되는지 이해할 수 있을 것이다.

angular.html

<!DOCTYPE html>
<html lang="en" ng-app class="no-js">
	<head>
		<meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
		<title>Data Binding Example</title>
	</head>
	<body>
    	<input type="text" ng-model="firstName" placeholder="first name">
        <input type="text" ng-model="lastName" placeholder="last name">
        <h2>gender { { gender } }</h2>
        <input type="radio" ng-model="gender" value="male" ng-click="style={color:'yellow'}">Male
        <input type="radio" ng-model="gender" value="female" ng-click="style={color:'blue'}">Female
        <br/>
        <h2 ng-style=style>Welcome </h2>
        <button ng-disabled="!(firstName.length && lastName.length)" ng-click="signUp()">Sign Up</button>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
	</body>
</html>

아마, 단순히 angular부터 공부하려고 하는 사람은 쉽게 이해 못할지도 모르지만, 위 HTML 코드를 만약 단순 javascript로 짜려면 상당히 스파게티코드를 조심해서 짜야 할 것이다.

단방향 데이터 바인딩양방향 데이터 바인딩의 차이를 좀 알면 위 코드가 이해하기 쉬운데,

단방향은 사실 간단하다. HTML은 페이지를 표시하기 전에 DB에서 데이터를 한번만 요구한다. 그리고 일단 브라우져에 표시되면 사용자는 DB데이터를 상호작용하거나 데이터를 바꾸는 작업이 불가능하고, HTML 형태로만 확인이 가능하다. 그렇기에 구현도 코드도 크게 복잡하지 않다.

그러나 대다수의 앱은 사용자의 입력을 받고, 상호작용으로 갱신이 된다.

단방향은 상당히 정적이기 때문에 모든 갱신 작업은 개발자가 직접 구현해야 한다. 만일 할 일 목록(to do) 서비스 웹앱을 만든다고 하자.

그럼 흐름적으로는 다음과 같다.

1. 사용자는 새로운 과업을 추가하기 위해 작은 폼을 채우고 Add 버튼을 누른다.

2. 메모리에 있는 자바스크립트 배열은 새로운 객체를 포함하도록 갱신된다.

3. 배열에 추가된 새로운 항목을 포함하도록 뷰도 갱신될 필요가 있다.

4. 자바스크립트 객체는 데이터베이스 갱신을 위해 웹 서버로 전송된다.

이 흐름이 올바로 이어지도록 유지해야 하는데, 심지어 이것만 있는게 아니라 삭제가 일어난다면 더욱 어렵다. 왜냐하면 위와 같은 흐름과 비슷하게 삭제함에 있어서도 뷰와 기반 객체 모델 사이에서 인위적으로 관계를 맺을 필요가 있기 때문이다.

특히 DOM이벤트와 DOM조작에 엄청나게 의존해야 한다. 사실 이런단계로 하려면 코드가 굉장히 복잡해 질 수 밖에 없다.

그럼 양방향 데이터 바인딩은 어떻게 할까?

데이터 모델과 뷰 동기화 문제를 쉽게 해결한다. 개발자가 직접 바인딩된 데이터를 조작할 때 DOM까지 동기화하는 작업에 관여할 필요가 없게 도와준다.

사용자가 입력함에 있어서 뷰도 동기화 시킨다고 하면 onChange와 onKeyUp과 같은 이벤트를 사용할 필요가 없어진다.

즉 위에 제시했던 예제를 다시 보면 잘 이해가 될 듯 하다.

사실 다른 책이나 위에서 언급했던 튜토리얼 자료들 전부 이런식으로 바인딩부터 들어가지는 않는다.

이 책이 난이도가 있다기 보다는 상당히 개괄적인것부터 들어가기 때문에 지식적인 면부터 채워 나가기에 훨씬 좋은 듯하다.

다른 튜토리얼은 표현식이나 코드를 적는 것이 많은데, 나는 책과 같이 기초를 기반으로 나아가길 원하므로 먼저 책 내용을 본 다음에 기본적인 문법으로 들어가도록 하겠다.


기술적인 개괄


apple

이제 데이터 바인딩이 앵귤러에서 정확이 어떻게 동작하는지 좀 더 깊게 보도록 하자.

본질적으로 데이터 바인딩은 스코프 객체(Angular Context)와 관련된 함수를 포함한다. 스코프 객체HTML 마크업을 위한 모델로 사용되는 앵귤러 생성자로 만든 자바스크립트 객체이다.

Angular 앱에서 스코프 객체는 컨트롤러를 거쳐 인스턴스로 만들어지며, 뷰에서 사용 가능 해진다. 하지만 아까 전에 본 예제에서는 프레임워크가 자동으로 생성한 전역 스코프를 사용하고 있다.

스코프 객체를 지배하는 규칙은 순수 자바스크립트 스코프 규칙과 유사하게 동작한다. 예를 들어 페이지에 여러 중첩된 앵귤러 스코프 객체가 있다면 내부 객체는 자신을 포함한 외부 스코프 객체를 볼 수 있고 접근할 수 있다.

$watch

UI에 데이터를 바인딩 할 때 마다 앵귤러는 자동으로 $watch 목록으로 알려진 곳에 새로운 $watch 항목을 생성한다.

$watch를 기반 데이터 모델이나 UI가 변경될 때 이벤트를 송수신 할 수 있는 작은 이벤트 전송기 정도로 생각하자.

UI에 바인딩된 모든 속성에 대해 $watch 항목 하나가 자동으로 생성된다. 이 것들은 다이제스트 루프에서 사용된다.

다이제스트 루프

관련된 Angular context가 반드시 처리해야 할 브라우저 이벤트(클릭, 변경, 키 누름)가 발생할 때 마다 다이제스트 루프가 실행될 것이다.

이는 루프가 아주 여러 차례에 걸쳐 실행 될 것임을 의미한다. 사용자가 firstName 입력 상자에 A라는 글자를 입력하면 루프가 실행된다. 기능 측면에서는 상대적으로 단순한데, $watch 목록에 있는 모든 항목을 순회하며 단계를 밟는다.

1. 루프는 현재 값을 객체에서 얻는다.

2. 루프가 실행된 마지막 시점 이후에 값이 변경 되었는지 물어본다.

3. $watch 항목 중 하나가 변경을 보고하면 또 다른 루프가 실행된다.

4. 변경을 보고하는 $watch 항목이 없을 때까지 실행된다.

5. 여기서 DOM은 객체층에 일어난 모든 변경사항을 반영, 갱신한다.

자, 자바스크립트는 단일 스레드다. 만약 다이제스트 루프가 시작되면 Angular가 스레드 제어권을 얻는다. 이는 루프과정에서 사용자 입력이 일시적으로 차단된다는 걸 의미한다.

양방향 데이터 바인딩의 동작 방식 덕분에 굉장히 많은 일의 범위가 줄어든다. 대부분의 데이터 바인딩 방식을 다 이해할 필요는 없고 사용법 정도만 알아도 된다.


단순한 컨트롤러


솔직히 말하면, 책의 내용이 굉장히 개론적인 것부터 잡고 들어가서 상당히 좋다. 다른 강의 같은 경우는 아마 동영상 8분만 봐도 지금보다 진도가 굉장히 나가고 있을 것이다.

code school에서 영상도 같이 보면서 작성중인데, 아직 6분대에서 끊겨 있다. codeacademy도 아직 첫 예제 이후로 진도를 못나가고 있는데, 이 책으로 좀더 개론을 쌓고 한번에 나간다면 훨씬 이해력이 높고 익숙해진 상태에서 갈 수 있기 때문에 여러 레퍼런스, 자료들이 있는게 확실히 더 좋은 공부법이라 생각한다.

그럼 본론으로 돌아오도록 하자.

분명 윗 예제는 앵귤러의 양방향 데이터 바인딩이 얼마나 강력한 지 보여준다. 하지만 실제로 앱은 이런 식의 구성이 되진 않는다.

앵귤러는 MVC 프레임워크가 핵심이고 윗 예제는 뷰만 있을 뿐이다.

이제 윗 예제를 스크립트를 넣어 완성할 것이다.

먼저 클릭버튼을 누르면 Ajax 요청을 서버에 전달하길 원한다고 가정하자. 지금은 여기에 관한 코드가 없는데 앵귤러 앱에 컨트롤러가 필요한 이유가 이것이다.

var app = angular.module('app',[]);
app.controller('main',['$scope',function($scope){
	$scope.firstName = $scope.lastName = undefined;
	$scope.gender = 'female';
	$scope.style = {color : 'orange'};
	$scope.signup = function(){
		var person = {
			first : $scope.firstName,
			last : $scope.lastName,
			gender : $scope.gender
		}

		console.log(person);
	};
}]);

이 것이 스크립트 코드다.

먼저 HTML에 연결하기 전에 2가지만 고치도록 하자.

하나는 ng-app 을 ng-app = "app" 이라고 하는 것body 태그에 ng-controller="main" 이라고 추가하는 것이다.

ng-app은 아까 설명했듯이 구축 중인 앱 이름이 app이며 새로운 app객체의 인스턴스를 만들 필요가 있다는 사실을 앵귤러에게 알려주는 것이다.

ng-controller는 body태그 내의 모든 엘리먼트가 스코프 콘텍스트로 main 컨트롤러를 사용해야 한다는 사실을 앵귤러에게 알려주는 것이다.

이제 위 자바스크립트 파일을 그대로 넣고 실행해 보도록 하자.

그럼 기본 내용이 제대로 출력되는 것이 보일 것이다.

사실 기본적인 기능은 뷰만 했을 때랑 비슷하다. 하지만 컨트롤러를 추가함으로서 body 내부에서 사용될 스코프 객체에 대해 더 많은 통제가 가능하다.

데이터 바인딩은 첫 예제와 마찬가지로 동일하게 기능해야 한다. 함수에 전달된 $scope 인자는 이 컨트롤러를 위한 콘텍스트 객체이다.

데이터와 함수가 이 컨트롤러에 바인딩 될 때 이 $scope 객체에 대한 참조를 얻는다.

지금은 좀 혼란스럽더라도 컨트롤러에 대해 다음 포스팅정도에 정리를 할 생각이니 조급해하지 않아도 된다.

지금은 전역 콘텍스트 대신 새로운 앵귤러 콘텍스트를 생성하여 동작 방식에 대해 더 많은 통제가 가능해 진다는 것을 알면 된다.


list를 사용한 데이터 바인딩


마지막 예제가 될 것이다.

데이터 바인딩이 가장 돋보이는 것이 목록 관리 기능이 상대적으로 수월하다는 것이다.

<!doctype html>
<html ng-app="app">
	<head>
		<meta charset="utf-8">
		<title>Data Binding Example</title>
	</head>
	<body ng-controller="main">
    	<input type="text" ng-model="firstName" placeholder="first name">
        <input type="text" ng-model="lastName" placeholder="last name">
        <button ng-disabled="!(firstName.length && lastName.length)" ng-click="add()">Add</button>
        <table>
        	<tr ng-repeat="p in presidents">
        		<td>{ {p.first} }</td>
        		<td>{ {p.last} }</td>
        		<td><button ng-click="$parent.remove(p)">Remove</button></td>
        	</tr>
        </table>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
        <script type="text/javascript">
        	var app = angular.module("app",[]);
        	app.controller('main',['$scope',function($scope){
						$scope.firstName = $scope.lastName = '';

						$scope.presidents = [{
							first : 'Abraham',
							last: 'Lincoln'
						},{
							first:'Andrew',
							last: 'Johnson'
						},{
							first:'Ulysses',
							last: 'Grant'
						}];
						$scope.add = function(){
							$scope.presidents.push({
								first: $scope.firstName,
								last: $scope.lastName
							});

							$scope.firstName = $scope.lastName = '';
						}
						$scope.remove = function(president){
							$scope.presidents.splice($scope.presidents.indexOf(president),1);
						}
        	}]);
        </script>
	</body>
	</html>

아마 위 예제를 그냥 자바스크립트로 짜봤던 사람은 굉장히 허탈감을 느낄지도 모르겠다 (개인적으로 나는 그랬다.) 사실 허탈감보다는 놀라움인데, 저 걸 짜려면 함수 몇개를 짜야하는지, ajax를 어떻게 맞춰 넣어야 하는지 얼마나 귀찮은 일인지 잘 알기 때문에 이렇게 간단히 짤수 있다는 것에서 angular에 대한 놀라움을 느낀다.

뭐 하여튼 설명을 해보자.

이번에 제시한 컨트롤러 또한 $scope 객체가 전달되었고, 이름 입력 부분은 크게 바뀐 것이 없다.

다만 밑에 대통령 목록이벤트 핸들러로 함수 두 개를 붙였다. 이 컨트롤러의 콘텍스트에서 값과 함수를 바인딩하기 위해 뷰가 $scope 객체를 사용한다는 사실을 기억하자.

삭제 버튼이 달린 대통령 테이블을 출력하는 것인데, 먼저 ng-repeat지시자이다. 이것은 해당 HTML과 내부의 모든 자식은 앵귤러 콘텍스트의 presidents 컬랙션(컨트롤러의 배열)에 속한 모든 항목을 대상으로 반복될 것이다.

이외의 작업도 많으나 문서를 읽어봐도 되고, 아마 추후에 다룰 일이 있지 않을까 한다.

또 다른 기능은 $parent.remove이다.

이것저것 스코프부터 구체적인 설명이 있지만 정리하자면,

다이제스트 루프가 add 혹은 romove시 돌게 되고, table을 다시 그리게 된다.

책에서도 나오지만, 이 것들을 jQuery와 자바스크립트로 그리면 스파게티 소스가 나올 가능성이 농후하다. 아마 angular를 나처럼 이제 쓰기되는 사람은 본인 프로젝트에 굉장히 바꿔야할 곳이 많을 것이다..


마치며


지금껏 사실 수박겉핥기 식으로 Angular의 기본적인 성질들에 대해 알아보았다.

DOM과 더불어 데이터를 새로 refresh시키는 작업을 굳이 하지 않아도 된다는 것이 얼마나 큰 일인지 알 수 있었다.

사실 코딩으로써 익숙해지고 배워가는 게 제일 빠르다. 책은 책답게 주변부터 차근히 정리해 갔지만, 아마 다음 포스팅부터는 직접 코딩도 많이 하며, 다른 자료들을 많이 활용하게 될 듯 하다.

Blog Logo

구찌


Published

Image

구찌의 나도한번 해블로그

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

Back to Overview