블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2013. 4. 11. 17:20 AngularJS/Concept

앵귤러의 모듈에 대해서 알아보자 



1) 개요

  - 모든 애플리케이션에는 main이 있지만 Angular에는 main 이 없다. 애플리케이션이 시작할 때 정의한 모듈을 읽는다

  - 모듈로 쪼개면 애플리케이션 이해가 쉽고 unit-testing이 수월하며 end-to-end testing도 가능하다

  - 필요한 모듈은 언제든지 로딩해서 사용할 수 있다

  - 3rd-party 라이브러리를 모듈로 만들어 사용할 수 있다 

  - Module API

  - 모듈 종류

    + Service Module

    + Directive Module

    + Filter Module 

    + module 들에 의존하는 Application Module : <ng-app="ModuleName"> 으로 시작


  - 모듈을 나누는 가장 큰 이유는 테스팅! 테스팅!

  - 아름다운 코드를 보자 

index.html

  1. <!doctype html>
  2. <html ng-app="xmpl">
  3. <head>
  4. <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
  5. <script src="script.js"></script>
  6. </head>
  7. <body>
  8. <div ng-controller="XmplController">
  9. {{ greeting }}!
  10. </div>
  11. </body>
  12. </html>


script.js : service, directive, filter module => use xmpl application module

  1. angular.module('xmpl.service', []).
  2. value('greeter', {
  3. salutation: 'Hello',
  4. localize: function(localization) {
  5. this.salutation = localization.salutation;
  6. },
  7. greet: function(name) {
  8. return this.salutation + ' ' + name + '!';
  9. }
  10. }).
  11. value('user', {
  12. load: function(name) {
  13. this.name = name;
  14. }
  15. });
  16.  
  17. angular.module('xmpl.directive', []);
  18.  
  19. angular.module('xmpl.filter', []);
  20.  
  21. <!-- ng-app="xmpl" 모듈이 다른 부가적인 모듈에 의존관계를 가지고 있다 -->
  22. angular.module('xmpl', ['xmpl.service', 'xmpl.directive', 'xmpl.filter']).
  23. run(function(greeter, user) {
  24. // This is effectively part of the main method initialization code
  25. greeter.localize({
  26. salutation: 'Bonjour'
  27. });
  28. user.load('World');
  29. })
  30.  
  31. // A Controller for your app
  32. var XmplController = function($scope, greeter, user) {
  33. $scope.greeting = greeter.greet(user.name);
  34. }

  


2) 모듈 로딩과 의존관계

  - 모듈은 초기화를 시작하여 애플리케이션에 적용되는 동안 Configuration & Run Block의 집합체이다 

  - Configuration Block

    + providers, constants 만 inject 된다

    + 의존관계있는 모듈을 inject 받는다 

  1. angular.module('myModule', []).
  2. value('a', 123).
  3. factory('a', function() { return 123; }).
  4. directive('directiveName', ...).
  5. filter('filterName', ...);
  6.  
  7. // is same as
  8. // config 펑션에 provider를 통하여 설정한다  
  9. angular.module('myModule', []).
  10. config(function($provide, $compileProvider, $filterProvider) {
  11. $provide.value('a', 123);
  12. $provide.factory('a', function() { return 123; });
  13. $compileProvider.directive('directiveName', ...);
  14. $filterProvider.register('filterName', ...);
  15. });


  - Run Block 

    + instances, constants 만 inject 된다

    + 모듈의 main 메소드 격으로 보면된다  


* Unit Test 다음에 추가



<참조>

  - 원문 : Developer Guide - Module

posted by 윤영식
2013. 4. 11. 11:50 AngularJS/Concept

Angular는 지시자(Directive)를 통하여 DOM을 확장한다. 지시자에 대해 자세히 알아보자



특징

  - Camel cased name 을 갖는다. 예) ngBind

  - 변환될 때는 Snake case - 으로 변경된다 예) ng-bind

  - 지시자는 element name, attribute, class name, comment 에 올 수 있다

  1. <span my-dir="exp"></span>
  2. <span class="my-dir: exp;"></span>
  3. <my-dir></my-dir>
  4. <!-- directive:my-dir exp -->


  - compiler는 $interpolate 서비스를 이용해서 text와 attribute를 매칭시킨다. 표현이 watch에 등록되어 있고, digest 싸이클의 일부로서 업데이트 되는 것이다 

<a href="img/{{username}}.jpg">Hello {{username}}!</a>


  - HTML에서 이루어지는 3 스텝

    + 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이 되는 것이다

  1. var $compile = ...; // injected into your code
  2. var scope = ...;
  3.  
  4. var html = '<div ng-bind="exp"></div>';
  5.  
  6. // Step 1: parse HTML into DOM element
  7. var template = angular.element(html);
  8.  
  9. // Step 2: compile the template
  10. var linkFn = $compile(template);
  11.  
  12. // Step 3: link the compiled template with the scope.
  13. 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 을 호출한다

  1. Hello {{user}}, you have these actions:
  2. <ul>
  3. <li ng-repeat="action in user.actions">
  4. {{action.description}}
  5. </li>
  6. </ul>


  - 정리

    + compile function : 지시자에 따라 template DOM 엘리먼트를 변환하여 특별한 DOM 엘리먼트를 만들어 준다 

    + link function : 지시자가 복제된 DOM 엘리먼트에 listener 등록하도록 해준다 



지시자 만들기

  - 전체 내역 

  1. var myModule = angular.module(...);
  2.  
  3. myModule.directive('directiveName', function factory(injectables) {
  4. var directiveDefinitionObject = {
  5. priority: 0,
  6. template: '<div></div>',
  7. templateUrl: 'directive.html',
  8. replace: false,
  9. transclude: false,
  10. restrict: 'A',
  11. scope: false,
  12. compile: function compile(tElement, tAttrs, transclude) {
  13. return {
  14. pre: function preLink(scope, iElement, iAttrs, controller) { ... },
  15. post: function postLink(scope, iElement, iAttrs, controller) { ... }
  16. }
  17. },
  18. link: function postLink(scope, iElement, iAttrs) { ... }
  19. };
  20. return directiveDefinitionObject;
  21. });


  - 기본 내역 : 없은 것은 기본값을 사용한다 

  1. var myModule = angular.module(...);
  2.  
  3. myModule.directive('directiveName', function factory(injectables) {
  4. var directiveDefinitionObject = {
  5. compile: function compile(tElement, tAttrs) {
  6. return function postLink(scope, iElement, iAttrs) { ... }
  7. }
  8. };
  9. return directiveDefinitionObject;
  10. });


  - 간단 내역 : 지시자가 템플릿 변환이 없고 자신의 인스턴스에 대한 것만 관련 있을 때 사용함 

  1. var myModule = angular.module(...);
  2.  
  3. myModule.directive('directiveName', function factory(injectables) {
  4. return function postLink(scope, iElement, iAttrs) { ... }
  5. });


  - Factory method : 지시자를 생성하는 역할이고, compiler가 지시자를 찾을 때 최초 호출하여 초기화 한다. $injector.invoke 를 사용한다 


  - 지시자 정의하기 

    + 지시자 정의는 compiler 에게 이렇게 이렇게 해달라는 설명을 제공하는 과정이다 

    + name : 현재 scope의 명칭 (optional)

    + priority : compile 펑션의 호출 우선 순위를 지정한다

    + terminal : true ?

    + scope : true 이면 새로운 scope 생성, {} 새로운 격리된 scope 생성으로 부모 scope 상속이 없다. 새로운 컴포넌트 만들 때 유용한다

      {} 로 만들때 안의 내용들 

        > @ : local scope property

        > = : bi-directional binding between local property and the parent scope property 

        > & : parent scope 에서 execute expression  방법을 제공 

///////////////

// @ 사용하기

/*
local scope property html
<div ng-app="drinkApp">
<div ng-controller="AppCtrl">
<div drink flavor="strawberry"></div>
</div>
</div>*/
 
var app = angular.module("drinkApp", []);
 
app.controller("AppCtrl", function($scope) {
$scope.ctrlFlavor = "blackberry";
})
 
app.directive("drink", function() {
return {
scope: {
flavor: "@"
},
template: '<div>{{flavor}}</div>'
/*
scope: {flavor: "@"} 표현은 link: function() {...} 과 완전히 동일하다
link: function(scope, element, attrs) {
scope.flavor = attrs.flavor;
}*/
}
})


///////////////

// = 사용하기 (소스)

/*
flavor="{{ctrlFlavor}}" 를 사용하지 않음에 주의한다
<div ng-app="drinkApp">
<div ng-controller="AppCtrl">
Ctrl
<input type="text" ng-model="ctrlFlavor">
Dir
<div drink flavor="ctrlFlavor"></div>
</div>
</div>
*/
 
var app = angular.module("drinkApp", []);
 
app.controller("AppCtrl", function($scope) {
// parent property
$scope.ctrlFlavor = "blackberry";
})
 
app.directive("drink", function() {
return {
scope: {
flavor: "="
},
// local property
template: '<input type="text" ng-model="flavor"> '
}
})


///////////////

// & 사용하기 (소스)

/*
message를 controller parent scope로 전달 이는 scope가 isolated되어 있어도 상위로 값을 전달 할 수 있게 한다
<div ng-app="phoneApp">
<div ng-controller="AppCtrl">
<div phone dial="callHome(message)"></div>
<div phone dial="callHome(message)"></div>
</div>
</div>
*/
 
var app = angular.module("phoneApp", []);
 
app.controller("AppCtrl", function($scope) {
$scope.callHome = function(message) {
alert(message);
}
})
 
app.directive("phone", function() {
return {
scope: {
dial: "&"
},
// {message:value} 객체를 통하여 contrller scope의 callHome에 전달
template: '<input type="text" ng-model="value">' +
'<div class="button" ng-click="dial({message:value})">Call Home</div> '
}
})


/////////////////////////

// @, =, & 종합 사용하기 (소스)

/*
@, &, = integration scope
<div ng-app="phoneApp">
<div ng-controller="AppCtrl">
<phone number="1111111" network="network" make-call="leaveVoicemail(number, message)"></phone>
<phone number="2222222" network="network" make-call="leaveVoicemail(number, message)"></phone>
<phone number="3333333" network="network" make-call="leaveVoicemail(number, message)"></phone>
 
</div>
</div>
*/
 
var app = angular.module("phoneApp", []);
 
app.controller("AppCtrl", function($scope) {
$scope.leaveVoicemail = function(number, message) {
alert("Number: " + number + " said: " + message);
}
})
 
app.directive("phone", function() {
return {
restrict: "E",
scope: {
number: "@", // local scope property
network: "=", // bi-directional binding between local property and parent property
makeCall: "&" // send expressions to parent scope
},
template: '<div class="panel">Number: {{number}} Network:<select ng-model="network" 
ng-options="network for network in networks">' +
'</select></div><input type="text" ng-model="value">' +
'<div class="button" ng-click="makeCall({number: number, message:value})">
Call Home</div> ',
link: function(scope) {
scope.networks = ["KT", "SKT", "LGU+"];
scope.network = scope.networks[0];
}
}
})

  

    + controller : pre-linking 전에 호출되어서 지시자들끼리 공유를 할려고 할때 사용

    + require : 다른 controller에 현재 지시자의 linking function을 전달 할때 사용용

    + restrict : 지시자 선언 종류 

  • E - Element name: <my-directive></my-directive>
  • A - Attribute: <div my-directive="exp"> </div>
  • C - Class: <div class="my-directive: exp;"></div>
  • M - Comment: <!-- directive: my-directive exp -->


    + template : HTML file 

    + templateUrl : 로딩할 URL 지정

    + replace : true 이면 현재 엘리먼트를 append가 아닌 replace 한다 

    + transclude : ngTransclude 엘러먼트로 컴파일 및 지시자로 쓰임 

    + compile : compile function 정의

    + link : link function 정의 


  - Compile function

    + template DOM을 변환하는 역할이다 

    + 사용자 정의할 때만 사용하면 되고 기존 지시자에는 사용할 일이 없겠다

function compile(tElement, tAttrs, transclude) { ... }

    + tElement : template element 

    + tAttrs : template attribute

    + transclude : transclude linking function: function(scope, cloneLinkingFn)

    + return 값을 두가지로 줄 수 있다

     > 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 로 읽을 수도 있다

  1. function linkingFn(scope, elm, attrs, ctrl) {
  2. // get the attribute value
  3. console.log(attrs.ngModel);
  4.  
  5. // change the attribute
  6. attrs.$set('ngModel', 'new value');
  7.  
  8. // observe changes to interpolated attribute
  9. attrs.$observe('ngModel', function(value) {
  10. console.log('ngModel has changed value to ' + value);
  11. });
  12. }



Transclusion 과 Scope 이해하기 

  - 재사용 컴포넌트를 만들고자 하는 다음의 경우를 생각해 보자 

    + show 버튼 클릭하면 다이얼로그 박스가 열린다

    + 다이얼로그 박스는 제목이 있고, 

  1. <div>
  2. <button ng-click="show=true">show</button>
  3. <dialog title="Hello {{username}}."
  4. visible="show"
  5. on-cancel="show = false"
  6. on-ok="show = false; doSomething()">
  7. Body goes here: {{username}} is {{title}}.
  8. </dialog>
  9. </div>

     + dialog 위젯이 변환되면 아마 하기와 같이 나올것이다 

      > username이 들어간 title을 넣어 줘야 한다 

      > onOk, onCancel 버튼이 동작해야 한다 

      > scope 에서 local 변수에 대한 맵핑작업이 필요하다 

  1. <div ng-show="visible">
  2. <h3>{{title}}</h3>
  3. <div class="body" ng-transclude></div>
  4. <div class="footer">
  5. <button ng-click="onOk()">Save changes</button>
  6. <button ng-click="onCancel()">Close</button>
  7. </div>
  8. </div> 


    + scope 정의 

     > transclude DOM 은 다이얼로그 위젯의 격리된 scope의 child 가 되어서 어느 것과도 binding되지 않고 영향을 미지치치 않고 title에 값을 맵핑할 수 있다. 즉, transclude scope는 original scope의 자식이 되기 때문이다 (아직 이해 실패^^;) 

  1. transclude: true,
  2. scope: {
  3. title: '@', // the title uses the data-binding from the parent scope
  4. onOk: '&', // create a delegate onOk function
  5. onCancel: '&', // create a delegate onCancel function
  6. visible: '=' // set up visible to accept data-binding
  7. },
  8. restrict: 'E',
  9. replace: true


  - Transclude 옵션을 설정하는 간단한 예제 (소스)

/*
Simple transclude sample dom
<div ng-app="phoneApp">
<div ng-controller="AppCtrl">
<panel>
<div class="button">Click me!</div>
</panel>
</div>
</div>
*/
 
var app = angular.module("phoneApp", []);
 
app.controller("AppCtrl", function($scope) {
 
})
 
// transclude: true와 <div ng-transclude를 설정하지 않으면 DOM의 <div class="button"이 안보이고 
// template의 내용만 보이게 된다. template 내용안에 DOM 의 button class가 같이 보이게 하기 위한 방법

> 버튼이 안보임


> transclude 설정으로 버튼이 보임


app.directive("panel", function() {
return {
restrict: "E",
transclude: true,
template: '<div class="panel" ng-transclude>This is a panel component</div>'
}
})


전반적으로 처음 접하는 개념이어서 정리가 서툴다. 다시 반복하여 리팩토링 예정임... ^^



미스코가 직접 이야기하는 Directive에 대해서 들어보자 

  - 유튜브 

    + Directive의 compile & link 개념의 C의 컴파일과 링크에서 영감을 받았다 

    + compile은 scope를 핸들링하지 않는다. template자체를 변경할 수 있다. 즉 compile은 template에 대한 해석만을 담당한다.

    + link는 element instance에 대해서 조작을 한다. 예로 element.addClass()와 같은 호출. 

    


  - 디렉티브 만들기 : 간단 총정리하기 

    


<참조>

  - 원문 : Developer Guide - Directives

  - AngularJS Directive로 컴포넌트 만들기 (필독)

  - 동영상강좌 : http://egghead.io

    + isolated @, =, & 소스 : https://gist.github.com/ysyun/5385927

    + 테스트를 위한 index.html 파일 내역 : CSS로 foundation을 사용한다 

 - Directives 이해 높이기-소스포함 (필독)

 - Directives Link, Apply, Digest 동작 흐름

posted by 윤영식
2013. 4. 10. 19:48 AngularJS/Concept

앵귤러군의 컴포넌트는 무엇이 있고 어떻게 상호작용하는지 알아보자 



Startup 

  - Angular는 어떻게 Hello World를 출력하는가?

  - 브라우져는 HTML를 로드하고 DOM객체로 파싱한다

  - DOMContentLoaded 이벤트가 발생하면 Angular 는 애플리케이션 경계를 결정해주는 ng-app 지시자를 찾는다

  - ng-app으로 명시된 모듈은 $injector를 환경설정한다 

  - $injector는 $compile & $rootScope를 생성한다 

  - $compile 서비스를 통해 DOM을 컴파일하고 $rootScope와 Link를 맺는다 

  - ng-init 을 통해서 scope 내의 name property에 World를 할당한다 

  1. <!doctype html>
  2. <html ng-app>
  3. <head>
  4. <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
  5. </head>
  6. <body>
  7. <p ng-init=" name='World' ">Hello {{name}}!</p>
  8. </body>
  9. </html>


  - 흐름도



Runtime

  - Angular와 브라우져간의 이벤트 루프를 돌며 상호 작용을 어떻게 하는가?

    + 브라우져 이벤트 루프는 이벤트 - 사용자 행위, 타이머, 서버응답에 대한 네트워크 이벤트등 - 발생을 기다린다

    + 이벤트의 콜백이 수행되고, JavaScript Context로 들어간다음 DOM 구조를 조작한다

    + JavaScript Context를 나오면 DOM 기반의 다시 그려진 화면으로 바뀐다 


  - 전통적인 JavaScript execution context 와 Angular execution context 동작 방식에 차이가 있다 

    + Angular execution context가 하는 일 : data-binding, exception 처리, 프로퍼티 변경 감시 등등

    + $apply를 통하여 JavaScript execution context에서 Angular execution context로 들어갈 수 있다

    + $apply의 직접호출은 사용자정의 이벤트 콜백과 3th-party 라이브러리 콜백일때만 사용하고 directive에서 자동 호출된다

    + 이에 대한 자세한 이해는 다음의 블로그를 꼭 읽어보길 바란다 : AngularJS and scope.$apply Posting


  - 다이어그램 이해 

    + scope.$apply(stimulusFn) 호출로 Angular Execution Context로 들어가고, stimulusFN은 이안에서 수행할 일이다 

    + Angular가 stimulusFn 을 수행하고 애플리케이션의 상태를 변경한다 

    + Angular는 다음으로 $digest 루프로 들어가고, 이는 $evalAsync 큐와 $watch 목록을 처리하는 작은 루프이다.   

    + $evalAsync는 현재 스택 프레임 외부에서 발생하는 스케쥴 잡에 사용된다 

    + $watch 펑션은 변경을 감지하고 DOM에 새로운 값으로 업데이트 하는 역할을 수행한다 

    + Angular 의 $digest 루프가 끝나면 Angular와 JavaScript context를 빠져나온다.  

   


  - 소스를 보고 다시 보자

    + Compilation 구간

      > ng-model과 input directive는 keydown시에 listener를 <input> 태그에 설정토록 한다

      > {{name}}은 $watch가 name 변경을 알 수 있게 설정토록 한다

    + Runtime 구간

      > H를 입력하면 브라우져가 keydown 이벤트를 발생시킨다 

      > input directive는 Angular Execution Context에서 모델값 업데이트를 위하여 값의 변경을 잡아서 $apply("name = 'H';") 를 호출한다 

      > Angular는 모델에 name = H 를 적용한다 

      > $digest 루프가 시작되고 $watch 는 name property 변경을 감지한 후 DOM을 업데이트 하도록 알려준다. 

      > 그런후 Angular Execution Context를 빠져나오고 keydown 이벤트와 JavaScript Execution Contex를 빠져나온다 

  1. <!doctype html>
  2. <html ng-app>
  3. <head>
  4. <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
  5. </head>
  6. <body>
  7. <input ng-model="name">
  8. <p>Hello {{name}}!</p>
  9. </body>
  10. </html>



Scope

  - scope는 모델 변경을 감지하고 표현하기 위해 Execution context 를 제공하는 책임을 갖는다 

  - scopes는 DOM 구조와 가깝게 하이어라키 구조를 갖는다 

  - 소스보기 

  1. <!doctype html>
  2. <html ng-app>
  3. <head>
  4. <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
  5. <script src="script.js"></script>
  6. </head>
  7. <body>
  8. <div ng-controller="GreetCtrl">
  9. Hello {{name}}!
  10. </div>
  11. <div ng-controller="ListCtrl">
  12. <ol>
  13. <li ng-repeat="name in names">{{name}}</li>
  14. </ol>
  15. </div>
  16. </body>
  17. </html>


 해당 소스에 대해서 이런 구조이다 



Controller 

  - controller는 뷰뒤에 있는 반드시 수행하는 코드이다

  - controller 역할은 모델을 생성하고 콜백 메소드를 가지고 view로 퍼블리싱을 담당한다 

  - view는 템플릿으로 Scope의 투영체이고, Scope는 Model과 View의 연결하며 controller로 이벤트를 보낸다 

  - view 와 controller 분리 이유 

    + controller 는 자바스크립트이고 업무적 행위를 정의한다. 또한 DOM rendering 정보가 일체 없다 

    + view template은 HTML이고 형태를 선언하고 행위는 없다 

  - Controller가 view를 인지하지 않으므로 많은 view 에 대한 처리를 담당할 수도 있다

  



Model 

  - 모델은 화면 템플릿에 합쳐지는 데이터를 가지고 있는 일반 자바스크립트 객체이다

  - Scope가 모델을 reference (참조) 하고 타입 제약을 갖지 않는다 

 



View 

  - 일반적인 것은 템플릿 스트링과 모델을 합쳐서 HTML을 만들고 DOM으로 해석되어 브라우져에 표현된다 

  - Angular는 템플릿이 HTML이어서 바로 DOM으로 해석되고 DOM안에 directive가 템플릿 엔진인 $compile 를 통해 $watch를 설정하고 모델의 변경을 계속 감시하게 된다. 따라서 모델값과 템플릿의 re-merging할 필요가 없게 된다. 

  - Angular Model은 화면에 대하여 single source-of-truth 이다 

 

  - 소스 : 동시에 바뀐다 

  1. <!doctype html>
  2. <html ng-app>
  3. <head>
  4. <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
  5. </head>
  6. <body>
  7. <div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
  8. <input ng-model="list" ng-list> <br>
  9. <input ng-model="list" ng-list> <br>
  10. <pre>list={{list}}</pre> <br>
  11. <ol>
  12. <li ng-repeat="item in list">
  13. {{item}}
  14. </li>
  15. </ol>
  16. </div>
  17. </body>
  18. </html>



Directives

  - 지시자는 HTML 을 확장하여 주고 행위를 일으키는 주체이다 

    + custom attributes

    + element name

    + class name 

// html

  1. <!doctype html>
  2. <html ng-app="directive">
  3. <head>
  4. <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
  5. <script src="script.js"></script>
  6. </head>
  7. <body>
  8. <div contentEditable="true" ng-model="content">Edit Me</div>
  9. <pre>model = {{content}}</pre>
  10. </body>
  11. </html>


// css

  1. div[contentEditable] {
  2. cursor: pointer;
  3. background-color: #D0D0D0;
  4. margin-bottom: 1em;
  5. padding: 1em;
  6. }


// js

  1. angular.module('directive', []).directive('contenteditable', function() {
  2. return {
  3. require: 'ngModel',
  4. link: function(scope, elm, attrs, ctrl) {
  5. // view -> model
  6. elm.bind('blur', function() {
  7. scope.$apply(function() {
  8. ctrl.$setViewValue(elm.html());
  9. });
  10. });
  11.  
  12. // model -> view
  13. ctrl.$render = function(value) {
  14. elm.html(value);
  15. };
  16.  
  17. // load init value from DOM
  18. ctrl.$setViewValue(elm.html());
  19. }
  20. };
  21. });



Filters

  - 데이터의 변환를 담당한다 

  - | 파이프를 사용한다 

  1. <!doctype html>
  2. <html ng-app>
  3. <head>
  4. <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
  5. </head>
  6. <body>
  7. <div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
  8. Number formatting: {{ 1234567890 | number }} <br>
  9. array filtering <input ng-model="predicate">
  10. {{ list | filter:predicate | json }}
  11. </div>
  12. </body>
  13. </html>



Modules and Injector

  - injector 는 Angular Application (ng-app) 에 하나만 존재한다 

  - injector는 명칭을 통해서 오브젝트 인스턴스를 찾는 방법을 제공한다 

  - 오브젝트 인스턴스에 대한 캐쉬를 가지고 있어서 생성된 것을 주거나 없으면 생성한다 

  - moduleprovider로 알려진 injector의 인스턴스 팩토리를 통해 환경 설정하는 방법이다

  


  - 소스

  1. // Create a module
  2. var myModule = angular.module('myModule', [])
  3.  
  4. // Configure the injector
  5. myModule.factory('serviceA', function() {
  6. return {
  7. // instead of {}, put your object creation here
  8. };
  9. });
  10.  
  11. // create an injector and configure it from 'myModule'
  12. var $injector = angular.injector(['myModule']);
  13.  
  14. // retrieve an object from the injector by name
  15. var serviceA = $injector.get('serviceA');
  16.  
  17. // always true because of instance cache
  18. $injector.get('serviceA') === $injector.get('serviceA');

 


$

  - $는 앵귤러의 오브젝트 명칭임을 나타내므로 가급적 충돌을 방지하기 위하여 $는 쓰지 말자 



Backbone.js & Angular.js 

  - angular는 62 page 부터 시작


  - 91 page : Angular Basic Service $로 시작  예) $q 

  - 92 page : 전역 API 예) element는 jQuery lite



<참조>

  - 원문 : Developer Guide - Concepts

  - 다양한 모듈들 : http://ngmodules.org/  ==> Angular안에서 Backbone사용하기 

  - Boostrap 연동 : http://angular-ui.github.io/

  - AngularJS & scope.$apply 의미

posted by 윤영식
2013. 4. 10. 17:35 AngularJS/Concept

애귤러군은 HTML을 어떻게 컴파일할까 알아보자 



1) 개요

  - HTML element 또는 attribute를 확장할 수 있게 해준다. 즉, 사용자 정의하여 새로운 HTML syntax를 브라우징할 수 있게 한다

  - Angular가 해석하는 Behavior Extension 을 directive 라고 한다 

  - Angular는 미리 번들링된 directives 들도 있지만 사용자가 만들 수도 있다 

  - 지시자의 해석은 서버에서도 미리 컴파일 되는 것도 아니다. 컴파일은 그냥 웹브라우저에서 수행한다  



2) 컴파일러

  - Compiler는 앵귤러 서비스이다 

  - 컴파일시 two phases

    + Compile : DOM/directives 해석

    + Link : scope를 가지고 directive를 결합시키고, 실시간 화면을 만든다. 모델이 변하면 뷰도 변하도록 바인딩한다

    예) ng-repeat : 성능향상을 위해 복제된 템플릿은 한번의 Compile이 필요하고, 각 복제된 인스턴스별로 한번 Link된다  



3) 지시자

  - 컴파일 과정에서 HTML 생성시 정의한 것과 매칭시키기 위한 행위자(Behavior) 이다. 

  - element name, attribute, class name, comment 에 놓일 수 있다

  - span 앨리먼트의 애트리뷰트로 사용한 draggable

  1. <!doctype html>
  2. <html ng-app="drag">
  3. <head>
  4. <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
  5. <script src="script.js"></script>
  6. </head>
  7. <body>
  8. <span draggable>Drag ME</span>
  9. </body>
  10. </html>



4) 뷰와 모델 바인딩

  - 일반적인 경우 

    + 데이터 변화면 다시 template과 model을 합쳐서 DOM안의 innerHTML 로 보여줘야 함

  



  - 앵귤러 경우

    + Angular compile가 지시자를 가지고 있는 DOM 을 템플릿으로 사용, linking function을 통해서 scope model 과 live view 바인딩을 해준다

    + 별도의 innerHTML 입력이나 이벤트 핸들링등의 코드가 전혀 필요없다 

  


<참조>

  - 원문 : Developer Guide - HTML compiler

posted by 윤영식
2013. 4. 10. 16:52 AngularJS/Concept

앵귤러의 시작 스텝에 대해서 알아보자 



1) 자동 초기화

  - <tag ng-app="name">

    + Angular는 DOMContentLoaded  이벤트가 발생하면 자동 초기화를 수행한다 

    + 이때 Angular는 애플리케이션 root를 만들어주는 ng-app 지시자(Directive)를 찾는다

    + Angular는 Directive 와 관련한 Module을 로드한다

    + 애플리케이션 injector 를 생성한다 

    + ng-app 지시자를 root로 해서 DOM을 Angular appliction으로 컴파일 해준다

  1. <!doctype html>
  2. <html ng-app="optionalModuleName">
  3. <body>
  4. I can add: {{ 1+2 }}.
  5. <script src="angular.js"></script>
  6. </body>
  7. </html>



2) 수동 초기화

  - ng-app을 사용하지 않는다

  - 모든 문서와 소스가 로딩된후 angular.bootstrap(RootDocument)를 컴파일 한다 

  1. <!doctype html>
  2. <html xmlns:ng="http://angularjs.org">
  3. <body>
  4. Hello {{'World'}}!
  5. <script src="http://code.angularjs.org/angular.js"></script>
  6. <script>
  7. angular.element(document).ready(function() {
  8. angular.bootstrap(document);
  9. });
  10. </script>
  11. </body>
  12. </html>



<참조>

  - 원문 : Developer Guide - Bootstrap

posted by 윤영식
2013. 4. 10. 16:38 AngularJS/Concept

AngularJS의 개발자 가이드를 요약해 본다. 



1) 개요

  - 데이터 바인딩에 {{}} 를 사용한다 : Data binding as in {{}}.

  - HTML안에 directives를 설정하여 제어한다 : DOM control structures for repeating/hiding DOM fragments.

  - 입력 폼에 대한 유효성 검사 : Support for forms and form validation.

  - HTML에 코드넣기 : Attaching code-behind to DOM elements.

  - 재사용가능 컴포넌트 형태의 HTML그룹핑 :  Grouping of HTML into reusable components.



2) 적합성

  - CRUD 시스템 개발에 잘 맞음

  - 게임이나, DOM 조작이 많은 GUI Editor등에는 안맞을 수 있고 오히려 jQuery가 잘 맞을 수 있다

  - DOM과 애플리케이션 로직을 분리하는데 최적 : MVC framework

  - Real Browser 테스트를 위하여 최적 : Karma

  - AJAX 통한 데이터 CRUD의 데이터 조작에 대한 반복코드 제거 

  - Guice 스타일의 필요한 모듈을 DI(Dependency Injection) 을 제공



3) 코드 이해

  1. <!doctype html>
  2. <html ng-app>
  3. <head>
  4. <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
  5. <script src="script.js"></script>
  6. </head>
  7. <body>
  8. <div ng-controller="InvoiceCntl">
  9. <b>Invoice:</b>
  10. <br>
  11. <br>
  12. <table>
  13. <tr><td>Quantity</td><td>Cost</td></tr>
  14. <tr>
  15. <td><input type="integer" min="0" ng-model="qty" required ></td>
  16. <td><input type="number" ng-model="cost" required ></td>
  17. </tr>
  18. </table>
  19. <hr>
  20. <b>Total:</b> {{qty * cost | currency}}
  21. </div>
  22. </body>
  23. </html>


  - ng-app : Angular가 애플리케이션을 자동 초기화 해주게 하는 지시자이다 

  - ng-model : 양방향 데이터 바인딩하고, 간단한 유효성검사도 수행 (유효하지 않으면 input 박스가 빨간색으로 변함)

  - <script src="http://code.angularjs.org/xxx/angular.min.js"> 에서 angular.min.js 버전별 호출

  - {{ expression | filter }} : 수식을 넣을 수 있고, | 를 이용하여 필터링 가능



<참조>

  - 개발자 가이드 : 개요

 

posted by 윤영식
prev 1 next