1. $scope
- $scope 는 양방향 데이터 바인딩의 핵심이자 뷰와 컨트롤러를 이어주는 징검다리이다.
사실 $scope는 그저 단순한 자바스크립트 객체에 불과하다 하지만 이 자바스크립트 객체는 연결된 DOM 요소에서 표현식이 계산되는 실행환경이며
뷰와 컨트롤러에서 사용되는 데이터(data)와 기능(function)이 살아 숨쉬는 공간이다.
또한 $scope는 위에서 보듯이 계층적 구조를 가진다.
1) $scope 특징
① 뷰와 컨트롤러를 이어주는 다리
② 연결된 DOM에서의 실행환경
③ 양방향 데이터 바인딩 처리
④ 이벤트 전파 처리
⑤ 계층적 구조
2) $scope와 컨트롤러의 관계
① AngularJS의 컨트롤러는 하나의 컨트롤러에 하나의 $scope만을 가지게 된다.
② 컨트롤러 함수 두 개가 있을 경우 컨트롤러 함수당 별도의 $scope 객체가 생성된다.
③ 그리고 AngularJS 어플리케이션 루트에 해당하는 $rootScope가 있다.
④ 하나의 화면에 여러 컨트롤러를 사용하면 컨트롤러 별로 독립된 $scope가 생성되는데 각 독립된 $scope는 서로 참조할 수 없다.
⑤ 그래서 컨트롤러 사이에 데이터를 공유해야 할 경우 서비스를 이용한다.
3) $scope의 계층구조
- 모든 AngularJS 어플리케이션은 하나의 $rootscope를 가진다.
- $rootscope는 ng-app을 생성하며 ng-app이 선언된 DOM 요소가 최상위 노드가 되어 여러 자식 $socpe를 가지게 된다.
즉, DOM과 같은 계층적 구조에서 최상위 계층에 $rootScope가 존재하는 것이다. 이는 어쩌면 window와 같은 글로벌 변수 영역이라고 생각할 수도 있다.
또한, ng-controller나 ng-repeat과 같이 별도의 $scope를 생성하는 지시자는 각 지역변수 영역을 가지고 있다고 생각할 수 있다.
<!DOCTYPE html><html ng-app='app'><head><meta charset="UTF-8"><script type="text/javascript" src="js/lib/angular.js" ></script><script type="text/javascript">angular.module('app', []).controller('parentCtrl', function($scope){$scope.parent={name: "parent Kim"};}).controller('childCtrl', function($scope){$scope.child={name : "child Ko"};$scope.changeParentName=function(){$scope.parent.name="another kim";};});</script></head><body><div ng-controller="parentCtrl"><h1>부모이름 : {{parent.name}}</h1><div ng-controller="childCtrl" style="padding-left:20px;"><h2>부모이름 : {{parent.name}}</h2><h2>자식이름 : {{child.name}}</h2><button ng-click="changeParentName()">부모이름 변경</button></div></div></body></html>
- 위 코드의 <html> 태그에 ng-app을 사용하면 $rootScope가 하나 만들어진다.
또한 <div ng-controller="parentCtrl">를 통해 $scope가 만들어지고 <div ng-controller="childCtrl">를 통해 또 하나의 $scope가 만들어졌다.
총 세 개의 $scope가 만들어 진것이다.
- 위 코드를 실행하면 childCtrl의 $scope가 parentCtrl의 $scope의 모델에 접근을 하며 값까지 변경을 하는데 이는 부모 $scope로부터 프로토타입을 상속 받기 때문에 가능한 것이다.
즉, 자식 #scope에서 없는 모델 즉, 속성을 부모 $scope에서 찾는다.
<$scope의 프로토타입>
4) Scope 타입
- $scope객체나 $rootScope 객체는 AngularJS내부에서 정의하는 Scope 타입의 인스턴스다.
즉 다음과 같이 별도의 생성자 함수가 AngularJS 내부에 정의돼 있다.
function Scope(){...}
Scope.prototype.$apply = function(){};
Scope.prototype.$digest = function(){};
Scope.prototype.$watch = function(){};
Scope.prototype.$new = function(){};
- AngularJS는 초기 부트스트랩 시 프레임워크 내부에서 $rootScope을 new Scope()와 같이 생성한 후 해당 $rootScope을 서비스로 제공한다. 그리고 ng-controller나 웹 어프리케이션
에서는 다음과 같이 $rootscope을 이용해 자식 $scope 객체들을 만들 수 있다.
var $scope = $rootScope.$new();
◈ scope 타입의 프로토타입 메서드
① apply(표현식 혹은 함수) : 주로 외부 환경에서 AngularJS 표현식을 실행할 때 사용한다. 즉, 외부 라이브러리로 이벤트를 처리할 때나 setTimeout 메서드를 사용할 때 사용한다.
인자로는 표현식이나 함수를 전달할 수 있다. 표현식을 전달하면 해당 표현식을 계산하고 함수를 전달하면 함수를 실행시키다.
그리고 내부적으로 $rootScope의 $digest를 실행해 등록된 모든 $watch를 실행하게 된다.
② $broadcast(이벤트 이름, 인자들...) : 첫 번째 인자인 이벤트 이름으로 하는 이벤트를 모든 하위 $scope에게 발생시킨다.
가령 $scope.$broadcast('popup : open', {title : "hello"}); 를 호출하면 $on 메서드를 이용해 해당 이벤트 (popup:open)을 듣고 있는 $scope들에게 {title : "hello"}의 데이터를 전달할 수 있다. 잘 활용하면 $scope들 사이의 참조 관계를 매우 느슨하게 만들어 재활용할 수 있는 UI 컴포넌트 개발에 용이하다.
③ $destroy() : 현재 $scope를 제거할 수 있다. 또한, 모든 자식 $scope까지 파괴한다.
④ $digest() ; $scope와 그 자식에 등록된 모든 $watch 리스너 함수를 실행시킨다. $watch 리스너 함수가 보는 표현식에 대하여 변화가 없다면 리스너 함수는 실행시키지 않는다.
⑤ $emit(이벤트명, 인자들...) : 해당 $scope를 기준으로 상위 계층 $scope에게 이벤트 명으로 인자를 전달한다. 물론 $on으로 이벤트 명을 듣고 있는 상위 계층에 한하여 전파한다.
⑥ $eval(표현식, 로케일) : 주어진 표현식을 계산하고 그 결과를 반환한다. 물론 현재 $scope를 기준으로 표현식이 계산된다.
⑦ $evalAsync(표현식) : $eval과 마찬가지나, 표현식의 결과값이 바로 반환되지 않고 나중에 어떠한 시점에서 그 결과가 반환된다. 하지만 적어도 한번의 $digest가 호출된다.
⑧ $new(독립여부) : 새로운 자식 $scope를 생성한다. 독립여부를 true, false로 전달하는 데 true일 경우 프로토타입을 기반으로 상속하지 않게 된다.
⑨ $on(이벤트 이름, 리스터 함수) : 주어진 이벤트 이름으로 이벤트를 감지하다가 해당 이벤트가 발생하면 리스너 함수를 실행한다. 이벤트 리스너 함수는 첫번째 인자로 이벤트 객체
를 받고 다음으로 $emit이나 $broadcast에서 전달한 값을 인자로 받는다.
⑩ $watch(표현식, 리스너 함수, 동등성 여부) : 대상 $scope에 특정 표현식을 감지하는 리스너 함수를 등록한다. 가령 $scope의 data 속성에 특정 객체가 할당되어 있다고 하자.
그리고 $scope.$watch("data", function(){...})로 함수를 호출하면 $scope.data의 레퍼런스가 변경될 때 리스너 함수가 호출된다.
리스터 함수에는 인자로 새로운 값과 이전 값이 주어진다. 동등성 여부는 변경을 레퍼런스로 감지할 것인지 동등한 여부로 감지할 것인지를 정할 때 사용된다.
기본값은 false이며 레퍼런스 변경시에만 리스너 함수가 호출된다.
⑪ $watchCollection(표현식, 리스너 함수) : 기본적으로 $watch와 같은 기능을 하며 대신 배열이나 객체에 대한 변경을 감지할 때 사용한다.
배열일 경우 새로운 배열 요소가 추가되거나 배열 요소들 사이의 순서가 변경되거나 배열요소가 삭제될 때마다ㅏ 리스너 함수가 호추로딘다.
객체일 경우 속성에 변경이 있을 때마다 리스너 함수가 호출된다.
◈ 위 함수를 사용 시점별로 묶으면...
① 데이터 바인딩 처리 시 : $apply, $digest, $watch, $watchCollection
② 사용자 정의 이벤트 처리 시 : $broadcast, $emit, $on
③ 표현식을 $scope 객체의 컨텍스트(context)에서 계산할 때 사용 시 : $eval과 $evalAsync
④ $scope의 생성과 파괴 처리 시 : $new, $destroy
- $scope객체는 scope 타입의 인스턴스이므로 프로토타입 상속에 의해 위 메서드를 사용할 수 있다.
'AngularJS' 카테고리의 다른 글
15. 모듈(Module) (0) | 2015.03.16 |
---|---|
14. $scope -2 ($scope에서 사용자 정의 이벤트 처리) (0) | 2015.03.11 |
12. MVC - 모델, 뷰, 컨트롤러 (0) | 2015.03.10 |
11. CSS 클래스/스타일을 동적으로 처리하기 위한 템플릿 (0) | 2015.03.10 |
10. <select> 요소 사용법 (0) | 2015.03.10 |