블로그 이미지
Peter Note
Web & LLM FullStacker, 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 Peter Note
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 Peter Note
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 Peter Note
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 Peter Note
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 Peter Note
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 Peter Note
2013. 4. 9. 10:49 Git, GitHub/GitHub

.gitignore 설정을 깜빡하고 설정하지 않은 상태에서 git remote(GitHub)로 push 하였을 경우 삭제하는 방법



1) 삭제하기 

  - webstorm의 .idea 디렉토리가 GitHub에 push가 되었음 

  - .idea 를 삭제하자 

  


  - 명령수행 3 단계계

$ ll

total 24

-rw-r--r--   1 nulpulum  staff   59  4  6 16:04 component.css

-rw-r--r--   1 nulpulum  staff  473  4  9 09:30 component.js

-rw-r--r--   1 nulpulum  staff  633  4  9 09:30 component.html

drwxr-xr-x  12 nulpulum  staff  408  4  9 09:30 ..

drwxr-xr-x   6 nulpulum  staff  204  4  9 09:30 .

drwxr-xr-x  12 nulpulum  staff  408  4  9 09:56 .idea

$ git rm -r --cached .idea

rm 'angularjs/component/.idea/.name'

rm 'angularjs/component/.idea/component.iml'

rm 'angularjs/component/.idea/dictionaries/nulpulum.xml'

rm 'angularjs/component/.idea/encodings.xml'

rm 'angularjs/component/.idea/jsLibraryMappings.xml'

rm 'angularjs/component/.idea/misc.xml'

rm 'angularjs/component/.idea/modules.xml'

rm 'angularjs/component/.idea/scopes/scope_settings.xml'

rm 'angularjs/component/.idea/vcs.xml'

rm 'angularjs/component/.idea/workspace.xml'

$ git commit -m "remove webstorm .idea directory"

[master 80de3cc] remove webstorm .idea directory

 10 files changed, 352 deletions(-)

 delete mode 100644 angularjs/component/.idea/.name

 delete mode 100644 angularjs/component/.idea/component.iml

 delete mode 100644 angularjs/component/.idea/dictionaries/nulpulum.xml

 delete mode 100644 angularjs/component/.idea/encodings.xml

 delete mode 100644 angularjs/component/.idea/jsLibraryMappings.xml

 delete mode 100644 angularjs/component/.idea/misc.xml

 delete mode 100644 angularjs/component/.idea/modules.xml

 delete mode 100644 angularjs/component/.idea/scopes/scope_settings.xml

 delete mode 100644 angularjs/component/.idea/vcs.xml

 delete mode 100644 angularjs/component/.idea/workspace.xml

$ git push origin master

Counting objects: 7, done.

Delta compression using up to 4 threads.

Compressing objects: 100% (4/4), done.

Writing objects: 100% (4/4), 472 bytes, done.

Total 4 (delta 2), reused 0 (delta 0)

To https://github.com/ysyun/prototyping.git

   cc17d3a..80de3cc  master -> master


  - .idea 디렉토리가 삭제되었음 


  - git rm 옵션들

$ git rm -r --help

usage: git rm [options] [--] <file>...


    -n, --dry-run           dry run

    -q, --quiet              do not list removed files

    --cached                 only remove from the index

    -f, --force               override the up-to-date check

    -r                           allow recursive removal

    --ignore-unmatch      exit with a zero status even if nothing matched




<참조>

  - 원문 : Remove directory from remote repositories

posted by Peter Note
2013. 4. 9. 09:56 AngularJS/Concept

재사용성을 위하여 사용자 정의 컴포넌트는 어떻게 만들 수 있는지 알아보자. Markdown 컴포넌트를 만들어 본다



1) 코딩하기 

  - <markdown> 태그안에 들어가는 마크다운 포멧을 해석하여 주는 showdown library는 GitHub에서 다운로드 받는다 

  - 해당 내용을 showdown 라이브러리에서 해석할 수 있도록 컴포넌트를 만든다 


  - 사전준비 

     + 소스복제 : git clone https://github.com/ysyun/prototyping

     + 모듈소스 : cd prototyping/angularjs/component


  - component.html 소스코드 

    + ng-app 태그를 통하여 어떤 모듈을 사용할지 지정

    + showdown 로컬에 다운로드

    + component.js 안에 myApp안에 사용할 markdown directive 를 정의한다

<!doctype html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>AngularJS Hello World using Directives</title>
<script src="http://code.angularjs.org/1.1.4/angular.min.js"></script>
<script src="../../underscore/underscore-min.js"></script>
     <script src="../../showdown/compressed/showdown.js"></script>
<script src="component.js"></script>
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<markdown>
[[MobiCon]](http://mobicon.tistory.com/)

This is Test
============
    'function() { console.log('hi youngsik'); }
</markdown>


</body>
</html>


  - component.js 소스코드 

    + angular.module 정의

    + ng-app=myApp 에 대한 모듈이며, 의존관계 없음

    + new Showdown.converter()를 통하여 마크다운 포멧 해석기 생성

    + 'E' : DOM Element 지정, A-attribute, C-class, M-comment (참조)

angular.module('myApp', [])
    .directive('markdown', function() {
        var converter = new Showdown.converter();
        return {
            restrict : 'E',
            link : function (scope, element, attrs) {
                var htmlDiv = converter.makeHtml(element.text());
                console.log(htmlDiv);
                element.html(htmlDiv);
            },
// template: '<textarea rows="10" cols="10"></textarea>'
        }
    })


** 소스 : https://github.com/ysyun/prototyping/tree/master/angularjs/component



2) 동영상

  - component-1
 
  - component-2



<참조>

  - 원문 : http://blog.angularjs.org/2012/05/custom-components-part-1.html

              http://blog.angularjs.org/2012/05/custom-components-part-2.html

posted by Peter Note
2013. 4. 5. 16:27 AngularJS/Prototyping

AngularJS를 가지고 Twitter Search 기능을 프로토타입핑한다. Angular에서는 jsonp를 어떻게 다루는지 살펴보자 



1) Twitter 검색

  - 검색어를 넣고 트위터로 jsonp 검색을 하고 결과를 출력한다


  - angularJS와 angularJS resource 를 사용한다

    + 서버사이드 데이터를 RESTful하게 가져오기 위한 방법을 제공한다

    + API : http://docs.angularjs.org/api/ngResource.$resource (1.1.4 소스)


  - 사전준비 

     + 소스복제 : git clone https://github.com/ysyun/prototyping

     + 트윗소스 : cd prototyping/angularjs/twitter


  - twitter.html 소스

    + <html ng-app="Twitter"> 를 반드시 추가한다. 설정하지 않으면 하기 에러발생. twitter.js에서 모듈명으로 사용


    + twitter.js angular controller 파일을 별도로 코딩한다

    + <div ng-controller="TwitterCtrl" 추가 

    + <input ng-model="searchTerm" 프로퍼티 추가하여 controller 내의 doSearch function 안에서 검색 파라미터로 사용한다 

    + <button ng-click="doSearch()" 추가하여 검색하기 버튼 클릭하면 호출될 function지정

    + <tr ng-repeat 추가 : angular $resource를 통한 jsonp 호출 결과를 리스팅한다 

<!doctype html>

<html lang="en" ng-app="Twitter">
<head>
<meta charset="UTF-8">
<title>AngularJS Hello World Twitter</title>
<script src="http://code.angularjs.org/1.1.4/angular.min.js"></script>
<script src="http://code.angularjs.org/1.1.4/angular-resource.min.js"></script>

<script src="twitter.js"></script>
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">

</head>
<body>

<div ng-controller="TwitterCtrl">
<form class="form-horizontal">
<input type="text" ng-model="searchTerm">
<button class="btn" ng-click="doSearch()">
<i class="icon-search"></i>Search
</button>
</form>

<table class="table table-striped">
<tr ng-repeat="tweet in twitterResults.results">
<td>{{tweet.text}}</td>
</tr>
</table>
</div>

</body>
</html>


  - twitter.js 소스 

    + angular.module : twitter.html에서 <html ng-app="Twitter" 명칭을 넣어줌. $resource를 사용하기 위하여 ngResource 의존

    + $scope.twitter.get() 호출하게 되면 jsonp 방식으로 호출하여 결과값을 가져온다

angular.module('Twitter', ['ngResource']);

function TwitterCtrl($scope, $resource){
$scope.twitter = $resource('http://search.twitter.com/:action',
{action:'search.json', q:'angularjs', callback:'JSON_CALLBACK'},
{get:{method:'JSONP'}});

// $scope.twitterResults = $scope.twitter.get(function(){ alert(' hi dowon jsonp '); });

$scope.doSearch = function () {
$scope.twitterResults = $scope.twitter.get({q:$scope.searchTerm});
}

}



2) 동영상


  - 소스 : https://github.com/ysyun/prototyping/tree/master/angularjs/twitter

posted by Peter Note
2013. 4. 5. 14:36 AngularJS/Prototyping

Backbone 으로 todo 목록을 처음 만들어 보았을 때 이해와 타입핑을 하는데 많은 시간을 소비하였다. Angular를 접하면서 Todo 목록 만들기가 얼마나 쉽고 빠르게 몇분만에 개발되는지 감상해 보자. 직접 해보았는데 20분정도 소요된것 같다. 그간 배운 빅데이터는 이와 같은 쉬운 웹앱기술로 통합되어 스마트 기기에 표현될 수 있겠다. 



1) 할일 목록 만들기 

   - 사전준비 

     + 소스복제 : git clone https://github.com/ysyun/prototyping

     + 투두소스 : cd prototyping/angularjs/todo


   - 할일 목록을 등록하고 완료체크를 하고 완료된 것은 삭제하는 기능을 갖는다

   

  - Bootstrap, Underscore를 이용하고, Angular Controller를 별도 .js로 분리한다 

  - todo.html

    + <html ng-app> 추가

    + <script> : angular.js, underscore.js, todo.js, bootstrap.css 파일을 연결한다

    + <div ng-controller> 추가 : controller function은 todo.js안에 구현 

    + getTotalTodos() : controller function 안에 구현 - 목록이 변경되면 자동 호출되어 바인딩됨 

    + <li ng-repeat> 추가 : todos 목록 배열을 열거한다 

    + <form> 의 <input ng-model="formTodoText"> 속성을 정의하고 controller function에서 사용토록 한다  

    + <button ng-click="clearCompleted()" 추가 : controller function에서 구현한다

<!doctype html>
<html lang="en" ng-app>
<head>
<meta charset="UTF-8">
<title>AngularJS Hello World using Directives</title>
<script src="http://code.angularjs.org/1.1.4/angular.min.js"></script>
<script src="../../underscore/underscore-min.js"></script>
<script src="todo.js"></script>
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="todo.css">
</head>
<body>

<div ng-controller="TodoCtrl">
<h2>Total count : {{getTotalTodos()}}</h2>
<ul class="unstyled">
<li ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.done">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
</ul>
<form class="form-horizontal">
<input type="text" ng-model="formTodoText" ng-model-instant>
<button class="btn" ng-click="addTodo()">
<i class="icon-plus"></i>Add
</button>
</form>

<button class="btn-large" ng-click="clearCompleted()">
<i class="icon-trash"></i>Clear Completed
</button>
</div>

</body>
</html>


    + 브라우져에 출력되는 DOM Element 소스 

    


  - todo.css

.done-true{
text-decoration: line-through;
color: grey;
}


  - todo.js

    + todos : 목록 배열

    + function들 정의

function TodoCtrl($scope) {

$scope.totalTodos = 4;

// 가상 데이터를 만든다
$scope.todos = [
{text:'Learn you', done:false},
{text:'build SPA', done:false}
];

// html에서 전체 건수를 return 해 준다
$scope.getTotalTodos = function() {
return $scope.todos.length;
}

// Underscore.js 를 이용하여 done=false 인 것만 배열로 뽑아낸다
$scope.clearCompleted = function() {
$scope.todos = _.filter($scope.todos, function(todo){
return !todo.done;
});
}

// todos 배열에 html에서 입력한 값을 넣어준다
$scope.addTodo = function() {
$scope.todos.push({text:$scope.formTodoText, done:false});
$scope.formTodoText = '';
}
}



2) TodoList 만들기 동영상

 

  - 소스 : https://github.com/ysyun/prototyping/tree/master/angularjs/todo

posted by Peter Note
2013. 4. 4. 17:59 AngularJS/Prototyping
AngularJS의 세계에 빠져보자.  BackboneJS 를 통하여 자유로운 영혼의 Client Side MV* framework 맛 보았다면 이제 AngularJS를 통하여 좀 더 절제되고 Fast Creating 가능한 방법에 대해 고민해 볼 때가 된 것 같다. 커뮤니티를 통하여 성숙하고 있고, 좋은 문서와 구글이라는 든든한 백그라운드까지 갖추고 있어서 무한한 성장 가능성을 가지고 있는 프레임워크라고 본다


1) Hello World
  - 구글 CDN 참조
  - 소스
<!doctype html>
<html lang="en" ng-app>
<head>
<meta charset="UTF-8">
<title>AngularJS Hello World</title>
</head>
<body>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js"></script>

<script>
function DowonController($scope) {

$scope.DowonProperty = "YoungSik";
}
</script>

<div ng-controller="DowonController">

<input type="text" ng-model="DowonProperty" ng-model-instant/>
Hello World

{{DowonProperty}}

</div>

</body>
</html>
 
  - 코딩 순서
    + angularJS CDN script 태그 추가 
    + <html ng-app> 추가
    + <div ng-controller> 추가 
    + controller function 구현 : $scope에 속성추가/설정
    + ng-model 추가 
    + {{ property }} 클라이언트 템플릿 추가 
    + 수행 : WOW!!!

  - 이해하기 
    + ng-app를 선언한 DOM 하위는 angular를 통하여 제어가 가능하다. 
    + ng-model을 HTML안에서 선언하면 controller function에서 프로퍼티를 사용할 수 있다
    + controller function에서 프로퍼티를 선언하면 HTML안에서 사용할 수 있다
    + 결국 Angular.js 는 양방향 Live Stream(Dynamic) binding을 가능하게 해준다  


2) 동영상
    


  - 소스 : https://github.com/ysyun/prototyping/blob/master/angularjs/hellworld.html



<참조> 

  - 동강 모음 http://johnlindquist.com/

  

  - 페이스북 공개그룹 : https://www.facebook.com/groups/frontiner/permalink/525021784200620/


AngularJS Hello World 
http://www.youtube.com/watch?v=uFTFsKmkQnQ&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

AngularJS - Getting Started - Google+
https://plus.google.com/communities/115368820700870330756/stream/f1fab692-830e-4341-b010-d0078e18719f

1. Devoxx 2012: AngularJS 
http://www.youtube.com/watch?v=4EVBg1pNdtc&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

2. Mastering AngularJS - 1. Introduction 
http://www.youtube.com/watch?v=DfstuptCfUo&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

3. Mastering AngularJS - 2. Using Directives .....감동의 도가니탕
http://www.youtube.com/watch?v=2SZQslQOgNg&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

4. AngularJS Tutorial .....감동의 도가니탕
http://www.youtube.com/watch?v=WuiHuZq_cg4&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

5. AngularJS Twitter Search 
http://www.youtube.com/watch?v=IRelx4-ISbs&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

6. AngularJS - Directive Tutorial 
http://www.youtube.com/watch?v=Yg-R1gchccg&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

7. AngularJS - Custom Components - Part 1 
http://www.youtube.com/watch?v=A6wq16Ow5Ec&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

8. AngularJS - Custom Components - Part 2 
http://www.youtube.com/watch?v=nKJDHnXaKTY&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

9. AngularJS - Communicating Between Controllers 
http://www.youtube.com/watch?v=1OALSkJGsRw&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

10. AngularJS and DOM Manipulation 
http://www.youtube.com/watch?v=bk-CC61zMZk&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

11. AngularJS - Handy Tricks With Developer Tools ...어려워 나중에
http://www.youtube.com/watch?v=4TM6wG9UW7s&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

12. AngularJS Routing ...............................................................내일은 여기서부터
http://www.youtube.com/watch?v=5uhZCc0j9RY&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

13. AngularJS - Behave like Gmail using Routes with Resolve 
http://www.youtube.com/watch?v=P6KITGRQujQ&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

14. AngularJS + Chosen Plugin = Awesome 
http://www.youtube.com/watch?v=8ozyXwLzFYs&list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz

posted by Peter Note
2013. 4. 3. 14:15 Testing, TDD/Test First

Node.js를 사용하기로 하면서 TDD를 위하여 Mocha를 선택하였다. 그리고 클라이언트단의 테스트 또한 Mocha로 이용해 보려 하였으나 DOM 조작이 많을 경우와 테스트 간결함등등에 강점이 많은 QUnit이 오히려 매력적으로 다가 왔다



1) QUnit vs Mocha

  - QUnit

    + DOM 조작관련 Client 단위 테스트에 적합

    + assert.equal이 아니라 equal만 사용하면 됨 

    + UI에서 테스트 모듈별로 콤보 선택하여 볼 수 있음

    + 클라이언트단 라이브러리들에서 주로 사용함 (BackboneJS 등)

    + PhantomJS와 연계하여 테스트

   



  - Mocha

    + 다양한 라이브러리를 접목 할 수 있다

    + 브라우져 UI 와 소스보기등이 QUnit 보다 나아 보임

    + equal 이 아니라 assert.equal을 씀 (assert의 경우) 즉, DRY 위배

    + UI에서 테스트 결과 전체가 리스팅 되고 선택하여 볼 수 없음 

 


** Backbone의 QUnit  코드를 Mocha를 가지고 메소드별로 TDD방식으로 테스트 해보았다. 라이브러리 테스트 코드를 하나하나 체크하면 전체 API의 동작방식을 심도 있게 이해 할 수 있다


https://github.com/ysyun/prototyping/tree/master/tdd/backbone-mocha/tests



2) 결론

  - 클라이언트 : QUnit + PhantomJS(CasperJS) 를 사용하여 테스트 진행

  - 서버 : Mocha + Assert 을 사용



<참조>

  - 원문 : Test  Libraries 비교 - 테스트 라이브러리별 사용처 권고함

posted by Peter Note

에릭리스가 이야기하는 린 스타트업은 이미 예전부터 있어 왔다. 그리고 나에게 현재 진행형이다. 

 Do it, Measure, Learn


  - 프로그래머는 현대판 락스타다. 컴퓨터 석학이 되려는게 아니다 그냥 이웃에서 도움이 되는 재미있는 뭔가를 하고 싶었다

    


  - 작은 것부터 시작하라. 린 스타트업의 MVP (Minimum Viable Product) 최소 요건 제품을 시장에 내놓고 평가받고 배워라

    

  - 다른 사람이 이용할 수 있는 당신만의 뭔가를 만들 수 있다. 그 진실을 깨달으면 당신의 삶은 영원히 바뀔 것이다
    


posted by Peter Note
2013. 4. 1. 19:41 Git, GitHub/GitHub

낚시성 제목이지만 한번쯤 링크를 걸어 놓고 궁금한 사항 발생시 첫번째로 확인해 볼 레퍼런스 사이트를 정리해 본다 



Git 메뉴얼

  - git-scm.com 의 한글 번역 메뉴얼

 




명령어 레퍼런스

  - gitref.org : 명령어에 대한 예와 다이어그램이 잘 나와있음






Merge 와 Diff Tool 바꾸기 

  - git의 기본적인 merge, diff 툴을 좀 더 괜찮은 넘으로 바꾸어 사용하기

  - p4merge 툴로 바꾸기 : 다운로드 받아서 설치한다

  - extMerge 파일 생성

/Users/nulpulum> cd /usr/local/bin

/usr/local/bin> cat extMerge

#!/bin/sh

/Applications/p4merge.app/Contents/MacOS/p4merge $*


  - extDiff 파일 생성

/usr/local/bin> cat extDiff

#!/bin/sh

[ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5"


  - 환경설정 명령 : git config --global <옵션>

// 옵션들 

merge.tool=extMerge

mergetool.extMerge.cmd=extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"

mergetool.extMerge.trustexitcode=false

diff.external=extDiff


  - ~/.gitconfig 내역 변경

[merge]

tool = extMerge

[mergetool "extMerge"]

cmd = extMerge \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"

[mergetool] <-- 제거

trustExitCode = false

[diff]

external = extDiff


  - 사용법은 p4merge 툴로 바꾸기 참조하시라





기초 문법 다시 보자 





Git 원리 이해하기 


posted by Peter Note
2013. 4. 1. 11:20 Middleware, Cloud/WAS

JVM에서 Thread Dump는 현재 수행중인 쓰레드에 대한 호출경로 StackTrace를 보기 위한 것이고 Heap Dump는 현재 Heap에서 점유되고 있는 객체들에 대한 조사를 위하여 필요한 내역이다 



1. Thread Dump 수행


  - 명령 : kill -3 <pid> 

  - <pid> 는 JVM의 process ID 이다 

  - Thread Dump 내역을 통하여 Thread ID와 호출에 대한 추적을 할 수 있다 

Full Java thread dump with locks info

"ZipFile Lock Reaper" Id=1826 in TIMED_WAITING on lock=java.util.TaskQueue@76a7850e

at java.lang.Object.wait(Native Method)

at java.util.TimerThread.mainLoop(Timer.java:509)

at java.util.TimerThread.run(Timer.java:462)


Locked synchronizers: count = 0


"ajp-0.0.0.0-8009-20" Id=1323 in WAITING on lock=org.apache.tomcat.util.net.AprEndpoint$Worker@12a2bc0f

at java.lang.Object.wait(Native Method)

at java.lang.Object.wait(Object.java:485)

at org.apache.tomcat.util.net.AprEndpoint$Worker.await(AprEndpoint.java:1989)

at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:2014)

at java.lang.Thread.run(Thread.java:662)


Locked synchronizers: count = 0


"ajp-0.0.0.0-8009-19" Id=1321 in RUNNABLE (running in native)

at org.apache.tomcat.jni.Socket.recvbb(Native Method)

at org.apache.coyote.ajp.AjpAprProcessor.readt(AjpAprProcessor.java:1072)

at org.apache.coyote.ajp.AjpAprProcessor.readMessage(AjpAprProcessor.java:1163)

at org.apache.coyote.ajp.AjpAprProcessor.process(AjpAprProcessor.java:368)

at org.apache.coyote.ajp.AjpAprProtocol$AjpConnectionHandler.process(AjpAprProtocol.java:425)

at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:2036)

at java.lang.Thread.run(Thread.java:662)

... 중략 ..




2. Heap Dump 수행


  - JVM GC 블로깅에서 Old영역을 많이 사용할 경우 일반적으로 사용되지 않는 객체들이 Reference되어 GC되지 않고 남아 있을 가능성이 높다. 이때는 어떤 객체들이 많이 점유되고 있는지 조사할 필요가 있다

  - 즉, Old 영역을 많이 점유하고 있으면 Full GC가 자주 오래동안 발생할 수 있으므로 업무 응답시간에 문제 또는 장애를 일으킬 소지가 있다

  - JDK6 명령 : jmap -dump:format=b,file=<fileName> <PID>    

  - jmap은 JDK_HOME/bin 에 포함되어 있음




3. Heap Dump 분석

 

  - Eclipse Memory Analyzer Tool (mat) 을 이용한다

  - 독립 프로그램 다운로드 : Heap Dump Size는 몇 Gbytes 씩 되므로 64bit OS 에서 64bit mat 를 다운로드 받는다

  - MemoryAnalyzerTool.ini 파일의 초기값 설정을 Heap Dump 파일 사이즈에 따라 적절히 한다

    + 내 경우 : -Xms2048m -Xmx8192m (Heap Dump file size 6Gbytes 일때) 

-XX:MaxPermSize=256m

-Xms40m

-Xmx512m


  - mat에서 Heap Dump 파일을 로딩한다. 이때 파일 확장자는 .hprof 여야 한다. 

    6Gbytes 로딩에 대략 수시간이 소요되니 인내심이 필요 하다  

  - mat 통하여 Heap Dump 분석할 때 로컬 메모리가 부족할 경우 Swap Size를 확장하여 준다 (스왑 설정하기)



<참조>

  - OOM 발생에 대한 고찰

  - Heap Dump 생성하기

  - Eclipse Memory Analyzer Tool Download

  - JHat 분석툴, JVisualVM 분석툴 (jdk1.6제공)

posted by Peter Note
2013. 3. 30. 16:23 Backbone.js

EmberJS를 익히는 방법에 대한 개념을 잡아보자



1) 개념잡기 

  - GitHub 메뉴얼 보기 

    + Binding : 프로퍼티 명칭뒤에 Binding을 붙여주면 변경에 대하여 자동 반영된다 

    + 계산된 속성 : 함수를 속성으로 다룰 수 있다 

    + 자동 업데이트 템플릿 : 자동 렌더링 in View


  - 홈페이지의 Guide 보기 

  - 가장 간단한 코드 


2) 기타 튜토리얼

  - ember.js 실습1


  - ember.js 실습2


  - ember.js 실습3



posted by Peter Note
2013. 3. 30. 12:33 Languages/CoffeeScript

CoffeeScript의 컴파일과 Minify, 하나의 파일로 만들기 그리고 자동 변경체크하여 컴파일 하기를 좀 더 쉽게 하는 Coffeebar를 알아보자 



1) Coffeebar 기능과 설치

  - 기능

Supports Literate CoffeeScript

Robust file watching

Cross-platform

Minification

Concatenation of multiple source files

Shows the actual source line when concatenated files have a compile error


  - 설치

$ sudo npm install -g coffeebar

/usr/local/bin/coffeebar -> /usr/local/lib/node_modules/coffeebar/bin/coffeebar

coffeebar@0.2.0 /usr/local/lib/node_modules/coffeebar

├── mkdirp@0.3.5

├── xcolor@0.1.0

├── coffee-script@1.6.2

├── commander@1.1.1 (keypress@0.1.0)

├── glob@3.1.21 (inherits@1.0.0, graceful-fs@1.2.0, minimatch@0.2.11)

├── beholder@0.1.2 (async@0.2.6, minimatch@0.2.11)

└── uglify-js@2.2.5 (optimist@0.3.5, source-map@0.1.19)



2) CLI 사용법

  - 옵션들

Usage: coffeebar [options] [path ...]


Options:


  -h, --help           output usage information

  -V, --version        output the version number

  -b, --bare           compile without a top-level function wrapper

  -m, --minify         minify output files

  -o, --output <path>  output path

  -s, --silent         suppress console output

  -w, --watch          watch files for changes


  - 컴파일 하기

$ coffeebar test.coffee


  - 소스 디렉토리(src)를 지정하여 컴파일 디렉토리(lib) 지정하기 

$ coffeebar src -o lib


  - 소스 디렉토리(src)를 지정하여 하나의 파일로 합치기

$ coffeebar src -o joined.js


  - 소스 디렉토리(src)를 지정하여 컴파일 디렉토리(lib) 지정하고 .coffee 소스 파일 변경되면 자동 컴파일하기 

$ coffeebar src -o lib -w



3) API 사용법

  - coffeebar(inputPaths, [options]) : inputPaths에 소스 디렉토리 지정하면 options에 따라 수행을 결정한다 

  - 옵션들

bare - (boolean) CoffeeScript compiler option which omits the top-level function wrapper if set to true.

minify - (boolean) Minify output files. Defaults to false.

output - (string) The path to the output file. If the path has a file extension, all files will be joined at that location. Otherwise, the path is assumed to be a directory.

silent - (boolean) Suppress all console output. Defaults to true.

watch - (boolean) Watch all files and directories for changes and recompile automatically. Defaults to false.


  - 예 : output 위치와 합칠 파일을 지정

// use the api in source

var coffeebar = require('coffeebar');

coffeebar('src', {output: 'lib/app.js'});


$ npm install

$ npm test



<참조>

  - 원문 : nmpjs.org coffeebar

posted by Peter Note
2013. 3. 27. 18:04 Dev Environment/Mac, Dev Tools

Chrome 의 Dev Tools에 Backbone/Ember/AngularJS 프레임워크 및 CoffeeScript Console을 확장해 본다. 

최종 확장한 모습이다 



1) CoffeeConsole 

  - 로컬에 파일 복제 : git clone https://github.com/snookca/CoffeeConsole.git

  - CoffeeConsole 폴더 밑에 coffeeconsole.crx 파일 존재

  - 크롬브라우져 URL 입력창에 chrome://extensions/  호출

  - coffeeconsole.crx 파일을 "확장프로그램 설치"창으로 drag&drop 하고 팝업창뜨면 설치 OK

  - 결과 확인 (크롬 : command+option+i)

  

  좌측에서 커피코드를 짜면 우측에서 실시간 해석되어 자바스크립트 코드가 보인다



2) BackboneJS

  - 로컬에 파일 복제 : git clone https://github.com/spect88/backbone-devtools.git

  - 크롬브라우져 URL 입력창에 chrome://extensions/  호출

  - "압축해제된 확장 프로그램 로드.." 버튼 클릭 -> backbone-devtools 폴더 선택하고 OK

  - [] Inject Backbone.Debug 를 선택하면 DevTools을 띄운 페이지가 reload된다 

  

  ** 결정적 단점은 AMD가 아직 지원이 안된다 ㅠ.ㅠ; 그냥 <script> 태그 통해서 BackboneJS 로딩해야 함

      window.Backbone available on DOMContentLoaded (no require.js support as of now, sorry)

  ** QUnit 이나 Mocha를 통하여 TDD 할 때 사용하면 된다. 



3) EmberJS

  - 로컬에 파일 복제 : git clone https://github.com/tildeio/ember-extension.git

  - 크롬브라우져 URL 입력창에 chrome://flags/ 호출하고 "실험실 확장 프로그램 API" 사용을 해야한다 

  - 크롬브라우져 URL 입력창에 chrome://extensions/  호출

  - "압축해제된 확장 프로그램 로드.." 버튼 클릭 -> backbone-devtools 폴더 선택하고 OK

  - Ember가 추가되었다  

  


4) AngularJS

  - 로컬에 파일 복제 : git clone https://github.com/angular/angularjs-batarang.git

  - 크롬브라우져 URL 입력창에 chrome://extensions/  호출

  - "압축해제된 확장 프로그램 로드.." 버튼 클릭 -> backbone-devtools 폴더 선택하고 OK

  - AngularJS 설치 화면 

  


Build Tool인 Grunt 또한 확장을 할 수가 있다. Grunt와 함께 확장툴은 사용하면서 다시 블로깅하기로 한다. 



<참조>

  - 원문 : DevTools Extensions in Chrome for Developers

posted by Peter Note
2013. 3. 26. 22:29 Dev Environment/Mac, Dev Tools

크롬을 사용하면서 개발이나 디자인시에 유용한 Extension을 설치하여 사용하자



1) 개발 및 디자인시 꼭 설치해야할 것들 

  - 25 가지 유용한 크롬용 익스텐션 툴들

    + 창 사이즈를 다양하게 띄워서 Responsive Web 테스트

    + Ruler를 통한 사이즈 크기 측정

    + FireBug lite for Chrome : 버그 있어서 제거함

    + Speed Tracer

    + Trello 는 Scrum 도구로 사용하고 있음 : PC, Android, iPhone, iPad 지원하는 서비스

    + getPocket 은 현재 보고 있는 화면 저장 및 태깅 : PC, Android, iPhone, iPad 지원 서비스

   



2) 크롬 Inspector의 바탕 스킨 바꾸기

  - 크롬 바탕색을 검은색으로 변경, 여러 스킨들 소개

  - chrome-devtools://devtools/devTools.css  호출하면 기본 css가 나옴

  - https://gist.github.com/bentruyman/1150520   의 Custom.css 파일로 대체한다 

    + Mac: ~/Library/Application Support/Google/Chrome/Default/User StyleSheets/Custom.css

    + PC: C:UsersYourUsernameAppDataLocalGoogleChromeUser DataDefaultUser StyleSheetsCustom.css


  - 검은색으로 나와서 좀 더 가독성이 높아진다  

    

    

** 현재 쓰고있는 것은 RubyBlue가 가장 가독성이 좋은 것 같다. 개인적 느낌으로...^^ (Custom.css.rubyblue.dowon)

Custom.css.zip

Custom.css.rubyblue.dowon



3) Mac에서 크롬 short key list

  - 크롬 hot keys

posted by Peter Note
2013. 3. 26. 18:29 Backbone.js

마리오네트는 엔터프라이즈 애플리케이션 개발시 필수적으로 갖추어야할 부분에 대한 고려사항이 반영되어 있으며 백본을 기본으로 확장하여 기능을 추가하였다. 마리오네트 공연을 보자



1) 마리오네트 장점

  - 모듈, 이벤트 지향 아키텍쳐의 확장

  - View에 대한 rendering 반복코드 줄여줌 

  - Region and Layout 개념을 통한 화면 통합

  - 메모리 관리 및 좀비 화면면/리젼/레이아웃등 관리

  - EventBinder 통한 이벤트 누수방지 (clean-up)

  - EventAggreagator 통한 이벤트 지향 아키텍쳐

  - 필요한 부분만 선택적으로 적용 가능



2) 반복 렌더링 코드

  - 백본 + 언더스코어 코드

    + View 에 대한 일반적인 define -> build -> render -> display == boilerplate code 라고 한다 

    + 이러한 코드가 애플리케이션 내에서 계속해서 반복된다 

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

// template file

<script type="text/html" id="my-view-template">

  <div class="row">

    <label>Name:</label>

    <span><%= name %></span>

  </div>

</script>


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

// 백본 View 코드 

var MyView = Backbone.View.extend({

  template: $('#my-view-template').html(),


  render: function(){

    // compile the Underscore.js template

    var compiledTemplate = _.template(this.template);


    // render the template with the model data

    var data = this.model.toJSON();

    var html = compiledTemplate(data);


    // populate the view with the rendered html

    this.$el.html(html);

  }

});


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

// 백본 App

var Dowon = new Person({

  name: 'Hi YoungSik'

});

var myView = new MyView({

  model: Dowon

});

myView.render();


//템플릿 결과 html 내역을 include

$('#content').html(myView.el)


  - Marionette의 ItemView 사용

    + render 메소드를 내장하고 있다. 즉 render 메소드가 제거되었다

    + Underscore를 기본 사용한다 

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

// 마리오네트 View 코드 

var MyView = Marionette.ItemView.extend({

  template: '#my-view-template'

});



3) 뷰의 Render 및 참조 오류 제거

  - View 인스턴스와 Event 핸들러를 메모리 관리 걱정없이 쉽게 다루도록 해준다 

  - 백본 코드

    + 하나의 뷰를 만들고 내부적으로 이벤트 핸들러를 등록한다 

    + 뷰의 변수에 두개의 레퍼런스가 할당되면 첫번째 뷰 객체는 좀비가 되지만 이벤트 핸들러가 2회 반응한다

       즉, View 의 render가 두번 호출되어 alert이 두번 뜸

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

// 좀비 View 만들기 

var ZombieView = Backbone.View.extend({

  template: '#my-view-template',

  initialize: function(){

    // bind the model change to re-render this view

    this.model.on('change', this.render, this);

  },

  render: function(){

    // This alert is going to demonstrate a problem

    alert('We`re rendering the view');

  }

}); 


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

// 수행

var Person = Backbone.Model.extend({

  defaults: {

    "name": "hi dowon"

  }

});


var Dowon = new Person({

  name: 'youngsik'

});


// create the first view instance

var zombieView = new ZombieView({

  model: Person

});


// 해결을 위하여 zombieView.stopListening(); 호출이 필요한다


// create a second view instance, re-using

// the same variable name to store it

zombieView = new ZombieView({

  model: Person

});

// set 호출하여 이벤트 trigger 발생

Person.set('name', 'yun youngsik');


  - Marionette 코드 

    + listenTo를 사용하면 중복된 이벤트 핸들러는 제거함 

var ZombieView = Marionette.ItemView.extend({

  template: '#my-view-template',

  initialize: function(){

    // bind the model change to re-render this view

    this.listenTo(this.model, 'change', this.render, this);

  },


  render: function(){

    // This alert is going to demonstrate a problem

    alert('We`re rendering the view');


  }

});



4) Region을 통한 View lifeCycle 자동 관리

  - 템플릿을 해석하고 데이터 맵핑후 jQuery를 이용하여 html()이용하여 템플릿 삽입하는 부분도 boilerplate 코드이다 

    위 예에서 $('#content').html(myView.el); 코드

  - View 메모리 문제처럼 화면에 보이는 부분을 Region 으로 사용하면 개별 View들에 대한 LifeCycle 을 관리해 준다 

  - DOM element를 관리하는 Region 을 생성하고 View의 관리를 Region에게 위탁한다 

    + el 을 지정한다

    + render의 구현은 필요없다

    + view에 대한 stopListening를 호출할 필요가 없고 자동으로 DOM에서 이전 view는 제거된 후 새로운 view가 render 된다다

// create a region instance, telling it which DOM element to manage

var myRegion = new Marionette.Region({

  el: '#content'

});


// show a view in the region

var view1 = new MyView({ /* ... */ });

myRegion.show(view1);


// somewhere else in the code,

// show a different view

var view2 = new MyView({ /* ... */ });

myRegion.show(view2); 



5) Application을 통한 Region 통합 관리

  - Marionette ToDoMVC AMD방식의 GitHub 소스를 통하여 살펴보자 (참조 문서에 없는 자체 분석 결과임)

    + git clone -b marionette https://github.com/derickbailey/todomvc.git  수행하여 clone 할 때 marionette 브랜치로 구성한다

       git clone https://github.com/derickbailey/todomvc.git  후에 git checkout marionette 해도 된다 

    + cd todomvc 디렉토리로 들어가서 static 수행한다 (8080 port)

    + 브라우져에서 바로 호출한다

       http://localhost:8080/labs/dependency-examples/backbone_marionette_require/index.html

    


  - backbone_marionette_require 의 index.html 의 body 태그 중요내역

    + todoapp 섹션안에 #header, #main, #footer selector가 존재

    + Require.js 를 통한 js 폴더 밑의 main.built.js 파일을 수행(Minified 파일) -> main.js 파일 수행함 

<body>

<section id="todoapp">

  <header id="header">

  </header>

  <section id="main">

  </section>

  <footer id="footer">

  </footer>

</section>

<footer id="info">

  <p>Double-click to edit a todo</p>

  <p>Created by <a href="http://github.com/jsoverson">Jarrod Overson</a></p>

  <p><a href="./index-dev.html">View the unbuilt version</a></p>

</footer>

<script src="../../../assets/base.js"></script>

<script data-main="js/main.built" src="./js/lib/require.js"></script>

...

</body> 


  - main.js 파일에서 AMD 모듈 환경설정

    + 마리오네트를 AMD 모듈에 넣는다. 최근 버전은 AMD버전이 있으므로 shim에 설정하지 않아도 됨

    + app.js 파일을 수행한다 

    + baseUrl 을 설정하지 않았으므로 현재 디렉토리가 된다 

require.config({

  paths : {

    underscore : 'lib/underscore',

    backbone   : 'lib/backbone',

    marionette : 'lib/backbone.marionette',

    jquery     : '../../../../assets/jquery.min',

    tpl        : 'lib/tpl'   // underscore micro template 

  },

  shim : {

    'lib/backbone-localStorage' : ['backbone'],

    underscore : {

      exports : '_'

    },

    backbone : {

      exports : 'Backbone',

      deps : ['jquery','underscore']

    },

    marionette : {

      exports : 'Backbone.Marionette',

      deps : ['backbone']

    }

  },

  deps : ['jquery','underscore']

});


require(['app','backbone','routers/index','controllers/index'],function(app,Backbone,Router,Controller){

  "use strict";


  // 애플리케이션 시작

  app.start();


  // 라우터에 컨트롤러를 설정함

  new Router({

    controller : Controller

  });


  // 백본 이력 시작

  Backbone.history.start();

});

 

  - app.js 에서 Application.addRegions를 통하여 화면 Fragment를 등록한다

    + 애플리케이션이 초기화 된후 Fragment의 히스토리를 시작한다 (참조)

    + collections/TodoList.js 파일은 Backbone.Collection 이다 

    + views/Header 형식은 각각 views/Header.js 로 연결되고 다시 templates/header.tmpl 파일과 연결된다 

       underscore micro template (tpl)을 사용하고 있다

// 마리오네트안에 

define(

  ['marionette','vent','collections/TodoList','views/Header','views/TodoListCompositeView','views/Footer'],

  function(marionette, vent, TodoList, Header, TodoListCompositeView, Footer){

    "use strict";


    // SPA 애플리케이션 1개를 생성한다 

    var app = new marionette.Application(),

        todoList = new TodoList();


    app.bindTo(todoList, 'all', function() {

      if (todoList.length === 0) {

        app.main.$el.hide();

        app.footer.$el.hide();

      } else {

        app.main.$el.show();

        app.footer.$el.show();

      }

    });


    // 리젼안에 화면을 담는다 

    app.addRegions({

      header : '#header',

      main   : '#main',

      footer : '#footer'

    });


 ... 중략 ...

});


  - Header.js 를 통한 Todo 입력하기 

    + todo 입력을 수행한다 

    + id="new-todo"   

    

    + 소스 

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

// views/Header.js

define(['marionette','templates'], function (Marionette,templates) {

  "use strict";


  // ItemView 을 상속 

  return Marionette.ItemView.extend({

    // templates/header.tmpl 파일을 참조 

    template : templates.header,


    // 템플릿 화면의 new-todo 아이디 

    // jQuery selected object를 가르키는 캐쉬된 속성을 input 이라고 생성한다 

    ui : {

      input : '#new-todo'

    },


    // 이벤트 설정 

    events : {

      'keypress #new-todo': 'onInputKeypress'

    },


    // 이벤트 핸들러 

    // 입력하고 엔터키 쳐지면 값을 컬렉션에 담는다 

    onInputKeypress : function(evt) {

      var ENTER_KEY = 13;

      var todoText = this.ui.input.val().trim();


      if ( evt.which === ENTER_KEY && todoText ) {

        // Collection에서 직접 Model객체를 생성함 

        this.collection.create({

          title : todoText

        });

        this.ui.input.val('');

      }

    }

  });

});


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

// templates/header.tmpl 

<h1>todos</h1>

<input id="new-todo" placeholder="What needs to be done?" autofocus>


  - TodoListCompositeView.js 를 통한 TodoList

    + header 밑으로 첨부된 todo list에 대한 태그입니다 

    


    + #todo-list 는 ul 태그안에  컬렉션이 리스팅된다 

    + 한개의 todo를 입력하였을 경우 : <ul id="todo-list> 태그안에  <li class="active">..</li> 내역이 동적으로 생성된다. 이것은 TodoItemView.js 가 된다. 

    + 즉, TodoListCompositeView.js는 TodoItemView.js 목록을 관리한다. itemView 속성에 지정한다

    + 좌측의 checkbox를 클릭하면 <li class="active"> 에서 <li class="completed">  로 변경된다 

    


// TodoListCompositeView.js

define(['marionette','templates','vent','views/TodoItemView'], function (Marionette,templates,vent,ItemView) {

  "use strict";


  return Marionette.CompositeView.extend({

    template : templates.todosCompositeView,

    itemView : ItemView,  // TodoItemView.js 

    itemViewContainer : '#todo-list',


    ui : {

      toggle : '#toggle-all'

    },


    events : {

      'click #toggle-all' : 'onToggleAllClick'

    },


    initialize : function() {

      this.bindTo(this.collection, 'all', this.updateToggleCheckbox, this);

    },


    onRender : function() {

      this.updateToggleCheckbox();

    },


    // 전체 checkbox 토글들에 대한 초기화 

    updateToggleCheckbox : function() {

      function reduceCompleted(left, right) { return left && right.get('completed'); }

      var allCompleted = this.collection.reduce(reduceCompleted,true);

      this.ui.toggle.prop('checked', allCompleted);

    },


    // 전체 todo 에 대한 토글

    onToggleAllClick : function(evt) {

      var isChecked = evt.currentTarget.checked;

      this.collection.each(function(todo){

        todo.save({'completed': isChecked});

      });

    }

  });

});


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

// templates/todoListCompositeView.tmpl

<input id="toggle-all" type="checkbox">

<label for="toggle-all">Mark all as complete</label>

<ul id="todo-list"></ul>


  - TodoItemView.js 

    + templates/todoItemView.tmpl 사용

    + todo를 더블클릭하면 class="active" 에서 class="active editing" 이 추가된다 

    


define(['marionette','templates'], function (Marionette,templates) {

  "use strict";


  return Marionette.CompositeView.extend({

    // 상단 <li class="active editing"> 태그를 표현 

    tagName : 'li',


    // todoItemView.tmpl 지정 

    template : templates.todoItemView,


    // <input class="edit" value="hi dowon"> 태그에 대한 jQuery selected object 를 가르킴

    ui : {

      edit : '.edit'

    },


    events : {

      'click .destroy' : 'destroy',

      'dblclick label' : 'onEditClick',

      'keypress .edit' : 'onEditKeypress',

      'click .toggle'  : 'toggle'

    },


    initialize : function() {

      this.bindTo(this.model, 'change', this.render, this);

    },


    onRender : function() {

      this.$el.removeClass('active completed');

      if (this.model.get('completed')) this.$el.addClass('completed');

      else this.$el.addClass('active');

    },


    destroy : function() {

      this.model.destroy();

    },


    toggle  : function() {

      this.model.toggle().save();

    },


    // 더블클릭을 하면 editing 중이라는 class가 추가되고 edit input 태그에 포커스가 가서 edit상태가 된다

    onEditClick : function() {

      this.$el.addClass('editing');

      this.ui.edit.focus();

    },


    // input 태그로 focus가 와서 입력후 enter를 치면 값을 넣고 editing class는 제거한다 

    onEditKeypress : function(evt) {

      var ENTER_KEY = 13;

      var todoText = this.ui.edit.val().trim();


      if ( evt.which === ENTER_KEY && todoText ) {

        this.model.set('title', todoText).save();

        this.$el.removeClass('editing');

      }

    }

  });

});


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

// todoItemView.tmpl

<div class="view">

  <input class="toggle" type="checkbox" <% if (completed) { %>checked<% } %>>

    <label><%= title %></label>

  <button class="destroy"></button>

</div>

<input class="edit" value="<%= title %>">


  - Footer.js 를 통한 Layout 개념이해 

    + Layout은 Region을 가지고 있다 

    + 좌측 완료안된 todo 건수 + 중앙 All, Active, Completed 상태별 todo 필터링 보기 + 우측 Clear Completed로 완료된 todo 제거 

    


    + 소스코드

// Footer.js 

define(['marionette','vent','templates','views/ActiveCount'], function (Marionette,vent,templates,ActiveCount) {

  "use strict";


  return Marionette.Layout.extend({

    // templates/footer.tmpl  

    template : templates.footer,


    // footer.tmpl의 id="todo-count" 밑의 <strong> 태그 

    regions : {

      count : '#todo-count strong'

    },


    // filters의 <a> 태그 

    ui : {

      filters : '#filters a'

    },


    // 제일 우측의 clear completed 

    events : {

      'click #clear-completed' : 'onClearClick'

    },


    initialize : function() {

      this.bindTo(vent, 'todoList:filter', this.updateFilterSelection, this);

    },


    // 리젼에 속한 count에 건수를 측정하는 ActiveCount 클래스에 컬렉션을 넘김

    onRender : function() {

      this.count.show(new ActiveCount({collection : this.collection}));

    },


    // All, Active, Completed <a> 태그의 class="selected"는 선택하는 곳으로 이동을 한다  

    // 또한 최상단의 <sectio id="todoapp" class="filter-active"> 또는 "filter-all", "filter-completed"로 변경됨 

    updateFilterSelection : function(filter) {

      this.ui.filters.removeClass('selected').filter('[href="#/' + filter + '"]').addClass('selected');

    },


    onClearClick : function() {

      vent.trigger('todoList:clear:completed');

    }

  });


});

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

// footer.tmpl

<span id="todo-count"><strong></strong> items left</span>

<ul id="filters">

  <li>

    <a href="#/">All</a>

  </li>

  <li>

    <a href="#/active">Active</a>

  </li>

  <li>

    <a href="#/completed">Completed</a>

  </li>

</ul>

<button id="clear-completed">Clear completed</button>


/////////////////////////
// views/ActiveCount.js
define(['marionette'], function (Marionette) {
  "use strict";

  return Marionette.View.extend({
    tagName : 'span',
    // collection에 변경이 있으면 다시 그려준다 
    initialize : function() {
      this.bindTo(this.collection, 'all', this.render, this);
    },
    render : function() {
      this.$el.html(this.collection.getActive().length);
    }
  });
});


쿨럭 목감기로 오늘은 여기까지 아무래도 Model/Collection 그리고 Marionette API 에 대한 분석이 필요해 보인다. 또한 TodoMVC 를 구현함에 있어서 개발 프로세스를 고려하여 분석하는 것이 맞을 듯하다. 다시 분석을 해보도록 한다 


<참조>

  - 원문 : Backbone.Marionette 

posted by Peter Note