+ Step 1: 최초에 Angular의 template은 HTML이므로 표준 브라우져 API를 사용하여 DOM 으로 파싱된다. 다른 템플릿 시스템과 차별점이기도 하다 (참조)
+ Step 2: $compile 메소드를 통해서 DOM을 해석하면서 지시자(directive)를 찾는다. 지시자는 $compile() 펑션이 수행되면서 DOM 구조를 변경하고 응답을 위하여 link() 펑션으로 return 한다
+ Step 3: 각 지시자별로 link() 를 호출하여 지시자별 listener등록과 scope에 대한 watch를 설정한다. 이에따라 scope와 DOM 사이에 Live Binding이 되는 것이다
var $compile =...;// injected into your code
var scope =...;
var html ='<div ng-bind="exp"></div>';
// Step 1: parse HTML into DOM element
vartemplate= angular.element(html);
// Step 2: compile the template
var linkFn = $compile(template);
// Step 3: link the compiled template with the scope.
linkFn(scope);
- 왜 compile과 link를 나눈거지?
+ model이 변경되면 DOM이 변경되어야 한다. 예) ng-repeat의 경우 model 목록이 늘면 DOM도 변경됨
+ {{user}}는 interpolation(값을 채우는) 지시자 이지만 ng-repeat은 ngRepeat 지시자이다. 여기서의 딜레마는 모델 데이터가 늘어나면 li 앨리먼트를 복제하여 compile과정을 또 거쳐야 하는데 그렇게 하면 성능이 느려진다. 이에 대한 해결책은 과정을 두개로 나누는 것이다. 그래서 ngRepeat 지시자를 해석하고 linking function 을 얻는다. ngRepeat 은 표현이 변경되면 li 엘리먼트를 복제하여 배열에 추가하고 새로운 scope 생성하여 복제한 li 엘러먼트에 할당하고 복제한 li 의 linking function 을 호출한다
Hello{{user}}, you have these actions:
<ul>
<li ng-repeat="action in user.actions">
{{action.description}}
</li>
</ul>
- 정리
+ compile function : 지시자에 따라 template DOM 엘리먼트를 변환하여 특별한 DOM 엘리먼트를 만들어 준다
+ link function : 지시자가 복제된 DOM 엘리먼트에 listener 등록하도록 해준다
> function 형태로 리턴 : linking function 으로 등록하는 것과 동일함
> object 형태로 리턴 : pre-linking, post-linking을 제어하고 싶을 때 사용한다
- Linking function
+ DOM 업데이트를 위하여 DOM listener를 등록하는 역할이다
+ template 이 복제된 후에 수행되고 지시자의 대부분 로직이 놓인다
function link(scope, iElement, iAttrs, controller){...}
+ scope : watch 등록할 때 지시자에 의해서 사용 됨
+ iElement : instance element.
+ iAttrs : instance attribute
+ controller : controller instance
+ pre-linking function : child element가 link 되기전에 호출
post-linking function : child element link 된 후에 호출
- Attribute Object
+ compile() 과 link() 에 파라미터로로 전달되는 객체
+ 값의 변화를 $observe 할 수도 있고 $set하거나 .XXX 로 읽을 수도 있다
function linkingFn(scope, elm, attrs, ctrl){
// get the attribute value
console.log(attrs.ngModel);
// change the attribute
attrs.$set('ngModel','new value');
// observe changes to interpolated attribute
attrs.$observe('ngModel',function(value){
console.log('ngModel has changed value to '+ value);
});
}
Transclusion 과 Scope 이해하기
- 재사용 컴포넌트를 만들고자 하는 다음의 경우를 생각해 보자
+ show 버튼 클릭하면 다이얼로그 박스가 열린다
+ 다이얼로그 박스는 제목이 있고,
<div>
<buttonng-click="show=true">show</button>
<dialogtitle="Hello {{username}}."
visible="show"
on-cancel="show = false"
on-ok="show = false; doSomething()">
Body goes here: {{username}} is {{title}}.
</dialog>
</div>
+ dialog 위젯이 변환되면 아마 하기와 같이 나올것이다
> username이 들어간 title을 넣어 줘야 한다
> onOk, onCancel 버튼이 동작해야 한다
> scope 에서 local 변수에 대한 맵핑작업이 필요하다
<divng-show="visible">
<h3>{{title}}</h3>
<divclass="body"ng-transclude></div>
<divclass="footer">
<buttonng-click="onOk()">Save changes</button>
<buttonng-click="onCancel()">Close</button>
</div>
</div>
+ scope 정의
> transclude DOM 은 다이얼로그 위젯의 격리된 scope의 child 가 되어서 어느 것과도 binding되지 않고 영향을 미지치치 않고 title에 값을 맵핑할 수 있다. 즉, transclude scope는 original scope의 자식이 되기 때문이다 (아직 이해 실패^^;)
transclude:true,
scope:{
title:'@',// the title uses the data-binding from the parent scope
onOk:'&',// create a delegate onOk function
onCancel:'&',// create a delegate onCancel function
visible:'='// set up visible to accept data-binding