하기 영상을 보면 JSON Object일 때와 String(Primitive type) 일때의 처리가 틀리다 왜그럴까 고민을 해보자
1. Angular.js scope 상속 방법
- childe scope는 기본적으로 parent scope를 상속받는다.
- 단, directive에서 scope : {...} 설정에서 scope isolate을 정하게 되어있다
- 원칙
1) define objects in the parent for your model, then reference a property of that object in the child: parentObj.someProp
부모 scope에 object를 정의하면 child scope로 상속 된다. 그러나 primitive type(string, number, boolean)은 상속되지 않는다
2) use $parent.parentScopeProperty (not always possible, but easier than 1. where possible)
$parent 의 프로퍼티를 사용한다. 항상 가능하진 않으나 1)번 보다는 쉽다
3) define a function on the parent scope, and call it from the child (not always possible)
부모 scope에 function을 정의하면 child scope로 상속 된다
2. JavaScript Prototypal 상속에 대하여
- scope chaing에 따른 상속 : childScope는 primitive, object 전부 호출 가능
3. Angular.js Scope 상속에 대하여
- 상속유형
1) The following create new scopes, and inherit prototypically: ng-repeat, ng-include, ng-switch, ng-view, ng-controller, directive with scope: true, directive with transclude: true.
ng-repeat, ng-include, ng-switch는 새로운 scope를 만들고 prototypically를 상속을 한다.
즉, scope:true, transclude:true인 directive이다 (새로운 scope를 만들지 않는 것은 scope: false 이다)
2) The following creates a new scope which does not inherit prototypically: directive with scope: { ... }. This creates an "isolate" scope instead.
prototypically사용을 하지 않고 새로운 scope를 만들려면 scope: {...} 를 정의하여 "isolate" scope를 만들어야 한다
- ng-include의 예
// controller 에서
$scope.myPrimitive = 50;
$scope.myObject = {aNumber: 11};
// html 에서
<script type="text/ng-template" id="/tpl1.html">
<input ng-model="myPrimitive">
</script>
<div ng-include src="'/tpl1.html'"></div>
<script type="text/ng-template" id="/tpl2.html">
<input ng-model="myObject.aNumber">
</script>
<div ng-include src="'/tpl2.html'"></div>
- 최초 설정 상태 : ng-include는 새로운 ChildScope1, 2를 생성한다. ParentScope는 ng-include를 감싸는 상위 Controller scope 가정
- 파란색 input box에 값을 입력 할 때 : primitive는 child scope에 새로운 property가 생성됨
- 분홍색 input box에 값을 입력 할 때 : object는 parentScope의 값이 변경됨
- 파란색을 분홍색처럼 영향을 미치고 싶다면 하기와 같이 사용하면 parent scope의 primitive 값을 child scope에서 제어가능
* 펑션도 Object와 동일하게 Child에 상속된다
<input ng-model="$parent.myPrimitive">
- ng-switch 도 ng-include와 유사하게 동작한다
4. ng-repeat 상속의 경우
- ng-include나 ng-switch와 약간 틀리다
// controller 에서
$scope.myArrayOfPrimitives = [ 11, 22 ];
$scope.myArrayOfObjects = [{num: 101}, {num: 202}]
// html 에서
<ul><li ng-repeat="num in myArrayOfPrimitives">
<input ng-model="num">
</li>
<ul>
<ul><li ng-repeat="obj in myArrayOfObjects">
<input ng-model="obj.num">
</li>
<ul>
- 최초 ng-repeat이 새로운 scope를 하나 만들고 iteration 하면서 아이템의 값을 새로운 scope를 또 만들어 새로운 property 에 할당함
여기서, 새로운 proeperty란 loop 변수 - 위의 예에서 num 또는 obj - 이다. 즉, 하기와 같은 작업이 일어나는 것이다.
childScope = scope.$new(); // child scope prototypically inherits from parent scope ...
childScope[valueIdent] = value; // creates a new childScope property
- 파란색 Primitive 배열 경우 : 새로운 scope가 생기고 loop 변수 num이 Childe scope에 생기고 primitive 값의 복사가 이루어진다.
즉, referencing 되지 않아 Parent Scope와 관련성이 없어진다
- 분홍색 Object 배열 경우 : Child Scope가 생성되고 loop 변수 obj는 parent scope의 배열 요소를 referencing 한다.
즉, child에서 변경을 하면 parent scope 값도 변경되는 것이다
- ng-controller
+ 일반적인 prototypal 상속을 따른다
+ controller 끼리 $scope를 통해 정보를 공유하는 것은 좋지 않다. 공유할려면 service를 이용한다 (참조)
- ng-view
+ ng-include와 동일하다
5. 사용자 정의 Directive의 Scope 경우
- directives를 만들 때
+ scope: false 는 기본값이다. directive를 만들면 scope를 새로 생성하지 않는다
+ scope: true 를 정의하면 일반적인 prototypal 상속을 따른다
+ scope: { ... } 경우는 isolate/isolated scope를 새롭게 생성한다.
- scope: {...} 경우 상세 고찰
1) prototypically 상속을 하지 않는다
2) 재사용 가능한 컴포넌트를 만들 때 사용한다. 즉 컴포넌트가 parent scope의 값을 read/write 못하게 한다
3) 그러나 간혹 parent scope에 접근(access) 하고 싶을 경우 object hash를 사용한다
'=' : two way binding (isolate scope <-> parent scope)
'@' : one way binding (isolate scope <- parent scope)
'&' : parent scope expressions 에 바인딩 된다
4) objec hash는 자신의 directive의 attributes 가 바인딩시에 이용됨을 주의한다
5) object hash 는 parent scope의 property를 지정 할 수 없다
즉, 'parentProp' 가 있을 때 <div my-directives>의 scope: {localProp: '@parentProp'} 지정로 하지 않고, 대신 접근하고 싶다면
<div my-directives the-Parent-Prop=parentProp> 의 scope: {localProp: '@theParentProp'}로 parent property를 명시해야 한다 (참조 예제)
6) isolate scope 의 attribute 명칭과 parent scope의 property 명칭이 같다면 scope: { attributeName: '=' } 이런식으로 설정함
틀리면 scope: { keyName1: '@isolateAttributeName', keyName2: '=isolateAttributeName'} 으로 정의함
- isolate scope 개념도
+ isolate scope 가 생성되면 __proto__ 는 Scope를 레퍼런스 한다 (하기 그림의 오랜지색 박스 'Object')
+ isolate scope의 $parent는 parent scope를 레퍼런스 한다. 그렇다고 prototypically 상속을 parent scope로 부터 하진 않는다
+ 하기와 같이 정의 하였을 경우
// html 에서 : attribute 에서 parent scope의 property를 접근한다
<my-directive interpolated="{{parentProp1}}" twowayBinding="parentProp2">
// directive 에서 : =, @, & 등을 사용하여 parent scope property의 접근 방법을 명시한다
scope: { interpolatedProp: '@interpolated', twowayBindingProp: '=twowayBinding' }
// directive의 linking function 에서
scope.someIsolateProp = "I'm isolated"
+ 위 코드이 개념도
- @ 을 사용하면 linking function안에 하기 코드를 사용한다.
즉, attrs.$observe('interpolated', function(value) { ... } 의 value에 11을 설정한다
attrs.$observe('attr_name', function(value) { ... }
- 따라서 scope.interpolatedProp는 linking function 안에 정의 되지 않으나,
scope.twowayBindingProp는 inking function 안의 정의 된다. 이에 대해 해당 링크를 참조하자 (예제)
6. Transclude 에 대하여
- transclude :true 하면 새로운 "transcluded" child scope를 생성한다. 이는 일반적인 prototypically 상속을 한다
- transaclude content가 two way binding을 원한다면 $parent를 이용한다
- isolate scope 객체와 transclude scope 객체는 형제지간으로 $parent는 같은 부모 object를 레퍼런스 한다 (sibling)
- isolate scope 의 $$nextSibling은 transclude scope 객체를 레퍼런스 한다
- 링크 사이트를 참조한다
즉, Isolate Scope를 가지게 되면 일반적인 Prototypal 상속을 따르지 않는다. 그러나 Isolate Scope(== Child Scope)가 간혹 parent scope를 접근하고 싶을 때는 @, =, & 와 같은 object hash를 Directive의 Attribute 앞에 붙임으로써 접근 방법을 지정할 수 있다.
* 주의) 버전 1.1.* 와 1.2.* 버전사이의 동작이 틀리다. 1.1.* 에서는 정상 작동하지만 1.2.* 에서 Isolate Scope방식이 정상 동작하지 않는다! (이유를 찾아봐야 함)
예제에서 왼쪽 메뉴의 "External Resource"를 바꾸어 가며 테스트해 보라
"http://code.angularjs.org/1.1.5/angular.js" <-> "http://code.angularjs.org/1.2.0/angular.js"
<참조>
- 원문 : Angular.js Scope에 대한 이해 개념도
- Angular.js Architecture 고려 사항 (필독)
- Angular.js Isolated Scope에 대한 이해 (필독)
'AngularJS > Concept' 카테고리의 다른 글
[Directive Driven] 하이브리드 앱 프레임워크 for Angular.js (0) | 2014.06.17 |
---|---|
[Directive Driven] Google Chart Directive 사용하기 (0) | 2014.06.04 |
[SPA] Modern Web에서의 Design Pattern 인식의 전환 (0) | 2013.09.28 |
[AngularJS] Service 종류 이해하기 (0) | 2013.08.22 |
[AngularJS] $watch, $apply, $digest 개념잡기 (0) | 2013.08.21 |