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

Publication

Category

Recent Post

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 윤영식