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

Publication

Category

Recent Post

2013. 4. 15. 11:44 Dev Environment/Build System

AngularJS 개발시 반복적인 작업을 제거하고 생산성을 높일 수 있는 통합 도구인 Yeoman의 사용법에 대해 알아보고, 처음 개발을 시작할 때 코드의 틀을 잡아 주는 몇가지 Seed 프로젝트를 통하여 어떤 구조로 애플리케이션을 만들어야 하는지 알아두자



1. 필요 요소 기술

  - UI : Bootstrap from Twitter  간혹 Foundation을 이용

  - Build/Preview : Grunt

  - Test : 기본은 Karma이고, Mocha를 사용하고 싶다면 Karma-Mocha Karma구동을 위한 Mocha adapter 존재

  - Package Management : Bower from Twitter

이들의 통합적으로 사용하기 위한 툴로 yeoman 을 설치하면 된다. 간단한 명령으로 AngularJS 관련 코드를 자동 생성하여 준다



2. Yeoman startup

  

yo - the scaffolding tool from Yeoman

bower - the package management tool  

  + component.json : 의존관계 설정

  + .bowerrc : 컴포넌트 설치 위치정보

grunt - the build tool 

  + Gruntfile.js : ant와 같은 수행 Task 정의

  + package.json : Node.js위에 구동되므로 package.json에 Grunt contributor 라이브러리 정의

karma - grunt test 시에 수행 

  + karma.conf.js : 로컬 테스트 환경

  + karma-e2e.conf.js : Real Browser 테스트 환경 즉, end-to-end (Client<->Server) 테스트 수행. 사용 port 8080


  - Yeoman command for AngularJS

// 설치 : grunt-cli, bower가 같이 설치된다 

npm install -g yo


// Yeoman을 위한 generator 설치 for AngularJS & Karam

// 하기 에러 내역 참조하여 generator-angular의 script-base.js 파일 수정

// Generator는 Yeoman에서 생성하는 boilerplate 나 scaffolding 코드를 만들어주는

// Yeoman의 플러그인이라 생각하면 된다. 이미 만들어지 Generator 목록이 존재한다

// > https://github.com/yeoman (generator-* 목록들)

// > Generator 만들기 참조

npm install -g generator-webapp generator-angular generator-karma


// 명령어 (프로젝트 디렉토리에서 수행)

yo angular 또는 yo angular:app 애플리케이션 생성

yo angular:controller myControllerName 컨트롤러 생성

yo angular:directive myDirectiveName 디렉티브 생성

yo angular:filter myFilterName 필터 생성

yo angular:service myServiceName 서비스 생성


  - yo angular:* 사용시 에러 발생 해결방법

예) yo angular:controller Test 수행시 하기와 같은 에러 발생

~/angularjs/sd_01> yo angular:controller Test


path.js:360

        throw new TypeError('Arguments to path.join must be strings');

              ^

TypeError: Arguments to path.join must be strings

    at path.js:360:15

    at Array.filter (native)

    at Object.exports.join (path.js:358:36)

    at Generator (/usr/local/lib/node_modules/generator-angular/script-base.js:38:29)

    at new Generator (/usr/local/lib/node_modules/generator-angular/controller/index.js:10:14)


==> 해결하기 

1) /usr/local/lib/node_modules/generator-angular/script-base.js 의 38 번째 줄 내용을 하기와 같이 수정함

 37     if (!this.options.coffee &&

 38       //this.expandFiles(path.join(this.appPath, '/scripts/**/*.coffee'), {}).length > 0) {  // 주석처리 

 39       this.expandFiles(path.join(process.cwd(), '/scripts/**/*.coffee'), {}).length > 0) {  // process.cwd() 로 바꿈

 40       this.options.coffee = true;

 41     }


2) 재수행 : 친절하게도 TestCase까지 자동 생성해 준다 

   ~/angularjs/sd_01> yo angular:controller Test

   create app/scripts/controllers/Test.js

   create test/spec/controllers/Test.js


  - Yeoman command for Bower : 의존관계 라이브러리에 대한 관리 담당 

// 명령어

bower search <dep> - search for a dependency in the Bower registry

bower install <dep>..<depN> - install one or more dependencies

bower list - list out the dependencies you have installed for a project

bower update <dep> - update a dependency to the latest version available


// 설치하기 

// .bowerrc 에 설정된 디렉토리로 다운로드된 라이브러리가 설치된다

$ bower install angular-ui

bower cloning git://github.com/angular-ui/angular-ui.git

bower cached git://github.com/angular-ui/angular-ui.git

bower fetching angular-ui

bower checking out angular-ui#v0.4.0

bower copying /Users/nulpulum/.bower/cache/angular-ui/bd4cf7fc7bfe2a2118a7705a22201834

bower installing angular-ui#0.4.0


$ cd app/components/

$ ls

angular angular-scenario es5-shim json3

angular-mocks angular-ui jquery


$ cd ../..

$ cat .bowerrc

{

    "directory": "app/components"

}


  - Yeoman command for Grunt : 프러덕션 빌드, 미리보기, 테스팅 

    + grunt는 task에 대한 여러 target들이 존재하는 구조이다. 

    + 명령을 grunt <task> 로 주면 task밑의 모든 target이 순서대로 수행된다

    + 명령을 grunt <task>:<target> 을 지정하여 특정 target만 수행할 수도 있다

    + task와 관련한 여러가지 Plugins 이 이미 만들어져 있고 직접 만들 수도 있다 (기존 Plugins 목록)

// 명령어

grunt test  - 테스트하기. run the unit tests for an app  

grunt server - 브라우져에서 보기. 변경사항 실시간 반영됨. preview an app you have generated (with Livereload)

grunt - 배포본 빌드하기.  build an optimized, production-ready version of your app  (warning 무시 옵션 --force 사용가능)


// 브라우져 미리보기 in app root folder

grunt server

// warning -jslint 같은- 무시하고 계속 build하기

grunt  --force 



3. 기본 코드 생성

  - Grunt-Express : Grunt와 Express 연동하기

  - Yeoman-Angular-Express : Yeoman을 이용하여 Angular project 생성한 후 Express와 통합하는 예제

  - Angular-Socket.io-Seed : Angular와 Socket.io를 접목 시키고자 할때 사용 (포스팅)



4. Addy Osmani 님이 이야기 하는 Automation Front-end workflow



결론적으로 Yeoman을 사용하여 기반 코드를 생성하고 빌드/테스팅 자동화를 한다. 그리고 필요한 코드들은 Seed 프로젝트를 참조하여 자기것으로 만들면 되겠다



<참조>

  - 원문 : Google, Twitter and AngularJS

  - 보다 많은 AngularJS와 BackboneJS에 대한 기사 in DailyJS

  - Grunt를 위한 express 플러그인 테스트

posted by 윤영식

AngularJS의 테스트툴로 Testacular를 사용하는데 명칭이 Karma로 바뀌었다. WebStorm에 설정하고 사용하는 방법을 알아보자 



1) Karma 설치하기

  - 홈페이지 : http://karma-runner.github.io/0.8/index.html

  - 선조건 : WebStorm 설치 및 Node.js 설치

  - Karma를 global로 설치 : npm install -g karma



2) Yeoman을 통한 Karma 환경설정 

  - 일반적으로 Yeoman을 통하여 스케폴딩 코드를 만들어 사용하는 것이 좋다 : Yeoman 홈페이지

  - yeoman 설치 : npm install -g yo grunt-cli bower

  - angular 프로젝트 만들기 : yo angular 또는 yo angular:app

    

    <자동 생성된 파일 및 디렉토리 구조>


  - 자동 생성된 karma 테스트 환경파일 : karma.conf.js

/ Karma configuration
 
// base path, that will be used to resolve files and exclude
basePath = '';
 
// list of files / patterns to load in the browser
files = [
JASMINE,
JASMINE_ADAPTER,
'app/components/angular/angular.js',
'app/components/angular-mocks/angular-mocks.js',
'app/scripts/*.js',
'app/scripts/**/*.js',
'test/mock/**/*.js',
'test/spec/**/*.js'
];
 
// list of files to exclude
exclude = [];
 
// test results reporter to use
// possible values: dots || progress || growl
reporters = ['progress'];
 
// web server port
port = 8080;
 
// cli runner port
runnerPort = 9100;
 
// enable / disable colors in the output (reporters and logs)
colors = true;
 
// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel = LOG_INFO;
 
// enable / disable watching file and executing tests whenever any file changes
autoWatch = false;
 
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers = ['Chrome'];
 
// If browser does not capture in given timeout [ms], kill it
captureTimeout = 5000;
 
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun = false;



3) WebStorm 환경설정

  - Server 설정하기 

    + 웹스톰 상단의 메뉴에서 Edit Configurations... 클릭

    

   + Node.js로 "Karma Server" 생성 : node.js, karma 설치 위치와 프로젝트 위치, 파라미터로 start 입력

      카르마의 테스트 서버 역할을 수행


    + Karma Run 생성 : 파라미터로 run 입력, 테스트를 수행한다 


    + Karma Debug : JavaScript Debug의 Remote로 생성 

       Remote URL 로 "http://localhost:8080/" 입력 



4) 테스트 수행하기 

  - Karma Server 시작하기 

    + Karma Server 선택하고 > 시작 버튼 클릭

    + 하단에 localhost:8080 으로 Listen하는 서버 구동됨 

    + 브라우져가 자동 실행 : 자동 실행안되면 브라우져 띄워서 8080 호출 



  - Karma Run 테스트 하기 

    + 테스트 수행하기 

    + 테스트가 정상 수행되면 SUCCESS가 나온다. 비정상이면 FAILED 메세지


  - Karma Debug

    + 소스 코드에 Break point를 만들고 디버그 수행

    + 테스트 해본 결과 잘 안되는데 향후 다시 한번 체크해 봐야 겠다



5) 테스트 코드 

  - BDD 방식의 테스트 코드를 짠다 

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

// 업무 코드 

'use strict';
 
var app = angular.module('eggheadioApp');
 
app.controller('MainCtrl', function ($scope) {
$scope.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];
}) ;
 
app.factory('Data', function() {
return {message: 'shared data'}
});
 
app.filter('reverse', function(Data) {
return function(text) {
return text.split("").reverse().join("");
}
});


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

// 필터에 대한 테스트 코드 

describe('filter', function() {
beforeEach(module('eggheadioApp'));
 
describe('reverse', function() {
it('should reverse a string', inject(function(reverseFilter){ //reverse라는 Filte 파라미터
expect(reverseFilter('ABCD')).toEqual('DCBA');
}))
})
})



<참조>

  - 원본 : 유튜브 동영상

posted by 윤영식
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 윤영식
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 윤영식
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 윤영식
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 윤영식
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 윤영식
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 윤영식
2012. 12. 29. 11:36 Backbone.js

View단위 MVC Framework으로 알려진 몇가지에 대해서 알아보자. MOVE solution으로 M=Model, O=Operation, VE=View 이다. 특히 View는 Logical DOM을 핸들링하게(Stream을 타고 즉, 동적으로 Storage지까지 가는 것이다. Stream=Function 이다.) 되고 MVC의 Controller 역할을 하게 된다. Operation은 단순 서비스/이벤트 역할이다. 대표적인 프레임워크가 BackBone이다. 

HTML -> Dynamic -> WebApp 그 정점에 SPA(Single Page Application)이 존재하고, 결국 최종 종착점은 고객에게 서비스하기 위한 View 기술이다. 여기에 필요한 전체 구조는 BackBone + Node.js + MongoDB 라고 보면되고, 이들은 Stream(Dynamic)하게 그러면서 Functional로 연력되어 Schemaless하게 움직이게 된다.



1) 전체 레밸의 MVC Framework

  - 브라우저 : BackBone.js

  - 서버 : Node.js위에서 구동되는 Express.js

  - 스토리지 : MongoDB위의 Mongoos 

* Node.js로 구성할 수 있는 Web App의 구성도



> BackBone.js 


> Ember.js


> Angular.js


3가지의 장단점에 대해서 검토해 보자 (다음번에 구체적으로 정리) O;TL

posted by 윤영식
prev 1 2 3 next