2014/08/04 00:41

  AngularJS(이하, 앵귤러) 기반의 싱글 페이지 웹 애플리케이션 개발에 대한 책을 집필하고 있다. 책안에 들어갈 내용을 위해 참조한 내역을 정리해 보고자 한다. 요즘 가장 큰 화두는 다양한 프론트 앤드 프레임워크가 나옴에 따라 프론트 앤드 개발에도 아키텍팅이 필요하다는 것이다. 프론트 앤드에서는 SPA(Single Page Application 이하, 싱글 페이지 웹 애플리케이션)가 앵귤러 프레임워크 기반으로 많이 소개 되고 있다. 싱글 페이지 웹 애플리케이션 접근 방식은 JSP, PHP같은 서버 템플릿이나 스프링 프레임워크에 익숙한 개발자에게는 생소한 개념이다. 


  싱글 페이지 웹 애플리케이션(SPA)은 "싱글 페이지 웹" 글자만 빼면 그냥 애플리케이션이다. 윈도우에 설치해서 사용하는 .exe 애플리케이션 개발 방식과 하등 차이가 없고 보여지는 기반이 브라우저안이라는 것 밖에 없다. 몇년전 리치 인터넷 애플리케이션(RIA)를 이끌었던 플랙스(Flex)를 떠올려도 좋다. 하지만 지금은 모바일과 웹의 시대이니 HTML/CSS/JavaScript 만으로도 충분히 애플리케이션을 만들 수 있어야 한다. 


  앵귤러는 애플리케이션을 만드는 프레임워크이다. 스프링 MVC 패턴의 개발을 했다면 앵귤러에서도 그렇게 할 수 있다. 스프링 의존성 주입의 편리함을 누리고 있다면 앵귤러에서도 그렇게 할 수 있다. 이제 웹의 세상에 맞는 애플리케이션 개발자로 거듭나 보자. 





 

저작자 표시 비영리 변경 금지
Posted by peter yun 윤영식
2014/08/04 00:11

Highchart에 대한 Directive를 만들며서 controller, compile, link 등을 써보고 있는데, 성능 최적화 및 실시간 데이터 업데이트 방법등에 대해서 고민하면서 좋은 글이 있어서 머리도 정리할 겸 따라쟁이 해본다. 



1. Directive 사용 영역

  - HTML안에서 element, attribute, class name, comment 4영역

<angular></angular>

<div angular></div>

<div class="angular"></div>

<!-- directive: angular -->



2. 이름 규칙

  - HTML안에서 하이픈(hyphens) 으로 단어 사이를 구분하여 사용

  - JavaScript안에서 단어사이는 대문자로 구분하여 사용

<div the-quick-silver-rider-youngsik></div>


App.directive('theQuickSilverRiderYoungsik', function() { ... });



3. 테스트전 SaaS

  - http://plnkr.co/  코드 테스트 Preview 서비스를 이용한다

  - GitHub 아이디로 로그인 한후 -> [Launch the Editor] 한다

  - 자신의 테스트 코드 및 타인의 코드를 서로 공유할 수 있다

  - 해당 서비스 자체가 AngularJS 기반으로 만들어 졌다 (Node.js + AngularJS 소스 공개)

  - 그림 오른쪽의 angular.js 라이브러리 버전을 선택하면 index.html에 자동 삽입되고 코딩을 시작할 수 있다



4. 간단한 테스트 수행

  - 사용자 정의 태그를 만든다

  - 이름 : angular

// index.html

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add the created custom 'angular' directive -->
    <angular></angular>
  </body>

</html>


// script.js

var App = angular.module('App', []);
 
App.directive('angular', function() {
  return {
    restrict: 'ECMA',
    link: function(scope, element, attrs) {
      var img = document.createElement('img');
      img.src = 'http://goo.gl/ceZGf';
 
 
      // directives as comment
      if (element[0].nodeType === 8) {
        element.replaceWith(img);
      } else {
        element[0].appendChild(img);           
      }
    }
  };
});


  - plunker preview


  - <angular> 태그에 <img> 태그가 추가되었다



5. Directive Definition

  - AngularJS는 기동될 때(bootstrapped), 사용자정의 및 빌트인된 directives를 찾고 $compile() 메소드를 이용하여 컴파일을 한다

  - compile 메소드 역할 : 모든 directives 요소를 찾아서 우선순위 sort하고 link function을 만든다. 또한 scope와 element사이의 2-way data binding을 위하여 $watch를 셋팅하거나 event listener를 생성된 (ng-app, ng-controller, ng-include, etc)같은 scope에 link한다  

  - Directive 정의

var myModule = angular.module(...);
myModule.directive('directiveName', function (injectables) {
  return {
    restrict: 'A',
    template: '<div></div>',
    templateUrl: 'directive.html',
    replace: false,
    priority: 0,
    transclude: false,
    scope: false,
    terminal: false,
    require: false,
    controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
    compile: function compile(tElement, tAttrs, transclude) {
      return {
        pre: function preLink(scope, iElement, iAttrs, controller) { ... },
        post: function postLink(scope, iElement, iAttrs, controller) { ... }
      }
    },
    link: function postLink(scope, iElement, iAttrs) { ... }
  };
});



5-1. Compile function

  - compile function이 link function을 만든다(produce)

  - 2개 파라미터

    + tElement : directive가 선언되어진 template element (jQuery object이다. 따라서 $로 다시 wrap하지 마라)

    + tAttrs : tElement와 관련된 모든 attributes 목록

  - ng-repeat같은 것을 사용할 경우 성능상의 이슈로 compile function이 사용된다. DOM과 scope객체를 연결지으려는데 데이터를 가져올 때마다 바인드과정을 거치지 않고 최초 한번 바인드되고 link functioin을 통해서 데이터 변경시에 scope-DOM간의 2-way 바인딩을 하여 변경을 반영한다

// in index.html

<div compile-check></div>


// in script.js

App.directive('compileCheck', function() {
   return {
     restrict: 'A',
     compile: function(tElement, tAttrs) {
       tElement.append('Added during compilation phase!');
     }
   };
 });


  - index.html에 <div compile-check></div>를 추가하고 script.js에 코드를 추가하면 하단에 'Added during compilation phase!'가 첨부된다



5-2. Link function

  - DOM과 scope 객체를 2-way data binding 하는 역할이다. compile function에서는 scope 객체에 접근할 수 없다

  - $watch 메소드를 통하여 사용자정의 listener를 생성할 수 있다. (register등록은 angular가 자동으로 해준다)

  - 3개 파라미터

    + element : directive와 바인드된 요소

    + scope : directive에 의해 사용되어지는 scope 객체

    + attrs : 요소와 관련된 모든 attribute목록

 


5-3. Restrict

  - E : elements

  - A : attributes

  - C : class name (CSS)

  - M : comments

  - HTML5 호환 표기가 가능한다 : 빌트인 ng-bind 사용

<span ng:bind="name"></span>
<span ng_bind="name"></span>
<span ng-bind="name"></span>
<span data-ng-bind="name"></span>
<span x-ng-bind="name"></span>



5-4. Template

  - html에 넣은 요소와 교체할 내역

  - html안의 태그 반복되는 부분을 별도의 모듈화로 중복을 방지 할 수 있다 

  - https://api.github.com/repos/angular/angular.js 호출하면 angular.js 관련 정보가 JSON 형태로 나옴

// index.html

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add controller & whoiam directive -->
    <div ng-controller="DemoCtrl">
      <div whoiam>This text will be overwritten</div>
    </div>
  </body>
 
</html>


// script.js

var App = angular.module('App', []);

App.run(function($rootScope) {
  $rootScope.header = 'I am bound to rootScope';
});
 
App.controller('DemoCtrl', function($scope) {
  $scope.footer = 'I am bound to DemoCtrl';
});
 
App.directive('whoiam', function($http) {
  return {
    restrict: 'A',
    template: '{{header}}<div class="thumbnail" style="width: 80px;"><div><img ng-src="{{data.owner.avatar_url}}"/></div><div class="caption"><p>{{data.name}}</p></div></div>{{footer}}',
    link: function(scope, element, attrs) {
      $http.get('https://api.github.com/repos/angular/angular.js').success(function(data) {
        scope.data = data;
      });
    }
  };
});


  - $scope는 $rootScope를 상속받기 때문에 template에서 {{header}}, {{footer}}를 호출 할 수 있다



5-5. TemplateUrl

  - 템플릿 마크업 및 별도의 html 파일로 관리한다

  - template 파일의 로딩을 빠르게 할려면 메모리에 적제하여 사용한다. $templateCache 

  - <script> 태그를 이용한다

<script type='text/ng-template' id='whoiam.html'></script>


  - inde.html 내역 : template script 태그를 head 태그안에 넣는다. id로 whoiam.html을 사용한다

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
   
    <!-- 3) add the template script tag -->
    <script type='text/ng-template' id='whoiam.html'>
      <div class="thumbnail" style="width: 260px;">
          <div><img ng-src="{{data.owner.avatar_url}}" style="width:100%;"/></div>
          <div class="caption">
            <p><b>Name: </b>{{data.name}}</p>
            <p><b>Homepage: </b>{{data.homepage}}</p>
            <p><b>Watchers: </b>{{data.watchers}}</p>
            <p><b>Forks: </b>{{data.network_count}}</p>
          </div>
        </div>
     </script>
  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 4) add controller & whoiam directive -->
    <div ng-controller="DemoCtrl">
      <div whoiam>This text will be overwritten</div>
    </div>
  </body>
 
</html>


  - script.js 내역 

var App = angular.module('App', []);

App.controller('DemoCtrl', function($scope) { });
 
App.directive('whoiam', function($http) {
  return {
    restrict: 'A',
    templateUrl: 'whoiam.html',
    link: function(scope, element, attrs) {
      $http.get('https://api.github.com/repos/angular/angular.js').success(function(data) {
        scope.data = data;
      });
    }
  };
});


  - 호출한 angular.js 정보가 출력된다



5-6. Replace

  - directive를 설정한 태그를 템플릿 태그로 교체하고자 할때 따라서 template 또는 templateUrl과 함께 사용한다

  - replace: true

  - index.html : elment, attribute, class name, comment 4가지 설정

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive -->
    <div angular></div>
    <div class="angular"></div>
    <angular></angular>
    <!-- directive: angular -->
  </body>
 
</html>


  - script.js 내역

var App = angular.module('App', []);

App.directive('angular', function() {
  return {
    restrict: 'ECMA',
    template: '<img src="http://goo.gl/ceZGf" />',
    replace: true
  };
});


  - 결과 html

// attribute

<img src="http://goo.gl/ceZGf" angular=""></img>


// class name

<img class="angular" src="http://goo.gl/ceZGf"></img>


// element

<img src="http://goo.gl/ceZGf"></img>


// comment

<img src="http://goo.gl/ceZGf" angular=""></img>


  - img 태그가 4개 생성되어서 이미지가 4개 보인다



5-7. Priority

  - 우선순위에 따라서 compile/link의 순위를 정한다. 값이 클 수록 우선순위가 높다

  - 이것은 미리 컴파일된 directive의 결과값을 체크하여 수행할 필요가 있을 때 사용한다

  - zero이면 priority 설정을 하지 않고 default priority를 사용한다

  - bootstrap의 'btn-primary' 클래스를 적용하려고 할때 index.html

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive -->
    <div style='padding:100px;'>
      <div primary btn>The Hitchhiker Guide to the Directive Demo by Dowon</div>
    </div>
  </body>
 
</html>


  - script.js 내역 : 우선순위로 btn이 먼저 생성되었으므로 primary에 대한 적용이 가능해 진다

var App = angular.module('App', []);

App.directive('btn', function($timeout) {
  return {
    restrict: 'A',
    priority: 1,
    link: function(scope, element, attrs) {
      element.addClass('btn');
    }
  };
});
 
App.directive('primary', function($http) {
  return {
    restrict: 'A',
    priority: 0,
    link: function(scope, element, attrs) {
      if (element.hasClass('btn')) {
        element.addClass('btn-primary');
      }
    }
  };
});


  - bootstrap의 btn-primary CSS가 적용된 버튼이 보인다



5-8. Terminal

  - 가장 최근에 수행된 directive에 terminal: true를 설정하면 그 이후 directive는 수행되지 않는다

  - index.html 내역

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive -->
    <div first second></div>
    <ul>
        <li ng-repeat="item in ['one', 'two', 'three']" no-entry>{{item}} </li>
    </ul>
  </body>
 
</html>


  - script.js 내역 : first -> second -> noEntry 가 수행되지만 second에 terminal: true 설정으로 매noEntry는 수행되지 않는다

  - ng-repate, ng-switch는 priority 높음에도 나중에 수행됨. 버그?

var App = angular.module('App', []);

App.directive('first', function() {
  return {
    restrict: 'A',
    priority: 3,
    link: function(scope, element, attrs) {
      element.addClass('btn btn-success').append('First: Executed, ');
    }      
  };
});
 
App.directive('second', function() {
  return {
    restrict: 'A',
    priority: 2,
    terminal: true,
    link: function(scope, element, attrs) {
      element.addClass('btn btn-success').append('Second: Executed ');
    }      
  };
});
 
App.directive('noEntry', function() {
  return {
    restrict: 'A',
    priority: 1000,
    link: function(scope, element, attrs) {
      element.append('No Entry: Executed ');
    }      
  };
});


  - first, second의 priority 값을 서로 바꾸어 보라 : 버튼의 text 순서가 바뀔 것이다. 또는 noEntry의 priority값을 1000이하로 하면 directive가 실행된다



5-9. Controller

  - Directive를 제어를 담당한다.

  - $scope, this 를 사용하여 properties/methods를 바인할 수 있다

  - this 키워드로 바인딩된 데이터는 require옵션을 사용하여 controller를 injecting함으로써 다른 directives에서 엑세스할 수 있게 한다.

  - 5-10의 require에서 예제 진행함

App.directive('powerSwitch', function() {
      return {
        restrict: 'A',
        controller: function($scope, $element, $attrs) {
          $scope.state = 'on';
 
          $scope.toggle = function() {
            $scope.$apply(function() {
              $scope.state = ($scope.state === 'on' ? 'off' : 'on');
            });
          };
 
          this.getState = function() {
            return $scope.state;
          };
        },
     };
});



5-10. Require

  - controller를 다른 directive에 전달해서 compile/linking function안에 연관시킬 수 있다

  - 같은 element 또는 부모와 바인드 되어야 한다

  - prefixed 부호가 붙는다

    + ? : 지정한 directive가 없더라도 에러가 발생시키지 않는다

    + ^ : 부모 element위의 directive를 찾는다. 같은 element위치는 유효하지 않다


  - index.html 내역 

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive : parent -> child depth  -->
    <div class="btn btn-success" power-switch>
      {{'Switched ' + state | uppercase}}
    
      <div lightbulb class='bulb' ng-class="bulb"></div>
    </div>
  </body>
 
</html>


  - script.js 내역

var App = angular.module('App', []);

App.directive('powerSwitch', function() {
  return {
    restrict: 'A',
    controller: function($scope, $element, $attrs) {
      $scope.state = 'on';
 
      $scope.toggle = function() {
        $scope.$apply(function() {
          $scope.state = ($scope.state === 'on' ? 'off' : 'on');
        });
      };
 
      this.getState = function() {
        return $scope.state;
      };
    },
    link: function(scope, element, attrs) {
      element.bind('click', function() {
        scope.toggle();
      });
 
      scope.$watch('state', function(newVal, oldVal) {
        if (newVal === 'off') {
          element.addClass('disabled');
        } else {
          element.removeClass('disabled');
        }
      });
    }
  };
});
 
App.directive('lightbulb', function() {
  return {
    restrict: 'A',
    require: '^powerSwitch',
    link: function(scope, element, attrs, controller) {
      scope.$watch(function() {
        scope.bulb = controller.getState();
      });
    }
  };
});


  - 변경내역 : toggle off일 경우

  <div class="btn btn-success ng-binding disabled" power-switch="">
     
      SWITCHED OFF
     
    <div class="bulb off" ng-class="bulb" lightbulb=""></div></div>


  - 결과 화면 : uppercase 필터 사용



5-11. Scope

  - scope가 hierarchy하게 생성/유지되면 element와 부모 element사이의 scope를 설정한다.

  - 그러나 자신은 부모 Scope하고만 바인드되어 data에 접근 할 수 있다. 최상위 scope는 $rootScope 객체이다

  - scope: false

    + 새로운 scope 객체를 만들지 않고 부모가 가진 같은 scope 객체를 공유한다

  - scope: true

    + 새로운 scope 객체를 만들고 부모 scope 객체를 상속받는다 


  - index.html 내역

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive : parent -> child depth  -->
    <div class='well'>
      Bound to $rootScope: <input type="text" ng-model="parent">
      <div child></div>   
    </div>
 
    <div class='form well' ng-controller="OneCtrl">
      ng-controller="OneCtrl"<br/>
     
      <input type="text" ng-model="children"><br/>
      I am {{children}} and my grandfather is {{parent}}
     
      <div child></div>
    </div>
  </body>
 
</html>


  - script.js 내역 : child 디렉티브의 link에서 conole.log(scope)를 찍어본다

var App = angular.module('App', []);

App.run(function($rootScope) {
    $rootScope.parent = 'ROOT';
});

App.directive('child', function() {
    return {
        restrict: 'A',
        // scope: false,
        scope: true,
        template: 'I am a directive and my father is {{parent}} as well as {{children || "NIL"}}',
        link: function(scope, element, attrs) {
            console.log(scope);
        }
    };
});

App.controller('OneCtrl', function($scope) {
    $scope.children = 'The One';
});


  - 결과화면 : child의 scope: true, false로 변경해 가면서 console.log의 내역을 비교해 본다

 

  - scope: true

// 첫번째 child의 $parent객체를 보면 ROOT이다


// 두번째 child의 $parent 객체를 보면 controller의 scope.children='The One' 값이 보임. 즉, controller scope가 부모이다


// Chrom에서 보면 scope 구조도가 보인다



  - scope: false

// 첫번째 child의 $parent객체를 보면 ROOT이다


// 두번째 child의 $parent 객체를 보면 ROOT 이다


// 002 는 ROOT scope 이고 그 밑으로 controller scope만 존재하고 child는 이것을 공유한다




  - scope: 'isolate'

    + 부모 scope를 상속받지 않는다. 그러나 scope.$parent로 부모 scope를 억세스 할 수 있다 

    + iscope.$parent을 사용하지 않고 isolated scope와 부모 scope간의 데이터 공유방법은 어떻게 하는가?

       isolated scope는 당신이 부모 scope로 부터 properties를 끌어내어 local scope와 바인드하는 object/hash를 갖는다  

       1) @ : 부모 scope property local scope 값을 바인딩한다. 원하는 값 전달시 {{}} 를 사용한다

       2) = : 부모 scope (전달전 측정되어질) property 를 직접 바인딩 한다  

       3) & : 속해있는 scope context안에서 수행될 expression 또는 method 바인딩 한다 

 

  - prefix parent property @, children property =, shout() method & 를 준 예제

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive : parent -> child depth  -->
    <div class='well'>
      Bound to $rootScope: <input type="text" ng-model="parent">
      <div child parent='{{parent}}' shout="shout()"></div>   
    </div>
 
    <div class='form well' ng-controller="OneCtrl">
      ng-controller="OneCtrl"<br/>
      <input type="text" ng-model="children"><br/>
      I am {{children}} and my grandfather is {{parent}}
      <div child parent="{{parent}}" children="children" shout="shout()"></div>   
    </div>

  </body>
 
</html>


  - script.js 내역

r App = angular.module('App', []);

App.run(function($rootScope) {
    $rootScope.parent = 'ROOT';
   
    $rootScope.shout = function() {
        alert("I am bound to $rootScope");
    };
});

App.directive('child', function() {
    return {
        restrict: 'A',
        scope: {
            parent: '@',
            children: '=',
            shout: '&'
        },
        template: '<div class="btn btn-link" ng-click="shout()">I am a directive and my father is {{parent || "NIL"}} as well as {{children || "NIL"}}</div>'
    };
});

App.controller('OneCtrl', function($scope) {
    $scope.children = 'The One';
   
    $scope.shout = function() {
        alert('I am inside ng-controller');
    };
});


  - 결과화면

 

  * scope: isolate 에 대한 이해는 egghead.io 사이트를 참조한다



5-12. Transcude

  - ngTransclude를 통하여 DOM에 transcluded DOM을 insert 할 수 있다

  - transclude: true
    transcluded DOM을 template에서 ngTransclude directive에 삽입한다

// index.html

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
    <!-- 3) template -->
    <script type='text/ng-template' id='whoiam.html'>
      <div class="thumbnail" style="width: 260px;">
        <div><img ng-src="{{data.owner.avatar_url}}" style="width:100%;"/></div>
        <div class="caption">
          <p><b>Name: </b>{{data.name}}</p>
          <p><b>Homepage: </b>{{data.homepage}}</p>
          <p><b>Watchers: </b>{{data.watchers}}</p>
          <p><b>Forks: </b>{{data.network_count}}</p>
          <marquee ng-transclude></marquee>
        </div>
      </div>
    </script>
</head>

<body style='padding:30px;'>
  <div whoiam>I got transcluded</div>
</body>
</html>



// script.js

var App = angular.module('App', []);

App.directive('whoiam', function($http) {
   return {
     restrict: 'A',
     transclude: true,
     templateUrl: 'whoiam.html',
     link: function(scope, element, attrs) {
       $http.get('https://api.github.com/repos/angular/angular.js').success(function(data) {
         scope.data = data;
       });
     }
   };
 });



// DOM 내역

<div whoiam="">

  <div class="thumbnail" style="width: 260px;"><div>

   <img style="width:100%;" ng-src="https://secure.gravatar.com/avatar/f0d91e5cf8ad1ce7972cc486baa20c42?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-org-420.png" src="https://secure.gravatar.com/avatar/f0d91e5cf8ad1ce7972cc486baa20c42?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-org-420.png"></img>

</div>


<div class="caption">

  <p class="ng-binding"> … </p>

  <p class="ng-binding"> … </p>

  <p class="ng-binding"> … </p>

  <p class="ng-binding"> … </p>

  <marquee ng-transclude="">

    <span class="ng-scope">
      I got transcluded
    </span>

  </marquee>

 </div>


// 결과 화면 : I got transcluded 메세지가 오른쪽에서 왼쪽으로 움직인다


  - transclude: 'element'

    + transclude link function을 compile function안에 정의한다

// index.html

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">
  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
</head>

<body style='padding:30px;'>
  <div transclude-element>I got transcluded <child></child></div>
</body>
</html>


// script.js

var App = angular.module('App', []);
App.directive('transcludeElement', function() {
    return {
        restrict: 'A',
        transclude: 'element',
        compile: function(tElement, tAttrs, transcludeFn) {

           // return 펑션이 link 펑션이 된다. 해당 펑션안에서 scope 객체 데이터 바인딩을 제어한다
            return function (scope, el, tAttrs) {
                transcludeFn(scope, function cloneConnectFn(cElement) {
                    tElement.after('<h2>I was added during compilation </h2>').after(cElement);
                });
            };
        }
    };
});

App.directive('child', function(){
    return {
        restrict: 'E',
        link: function($scope, element, attrs) {
            element.html(' with my child');
        }
    };
});


// DOM 내역

<body style="padding:30px;">
      <!-- transcludeElement:  -->
    <div class="ng-scope" transclude-element="">
      I got transcluded
      <child>
         with my child
      </child>

    </div>

    <h2>
      I was added during compilation
    </h2>

</body>


// 결과 화면



<참조>

  - 원문 : The Hitchhiker’s Guide to the Directive

  - Scoep Isolate 참조 : egghead.io 사이트

  - Yeoman 사용하기

저작자 표시 비영리 변경 금지
Posted by peter yun 윤영식
2014/08/03 23:26

AngularJS를 배우기 위해 좌충우돌 하며 읽고, 보고, 듣고, 코딩해본 코스를 나름 정리해 보았다. 



1. 개념잡기

  - Angular's father인 미스코님의 AngularJS 소개 동영상을 본다 : 단계별로 jQuery와 잘 비교하고 있다

    

  - Art of AngularJS를 보고서 이제 배워야할 필요성을 느껴보세요. 이제 시작하세요. 

    


  - AngularJS의 중요 요소와 기본기를 다져보자 (60분 동강)

    

     + AngularJS 전체 구성 요소 : 각각에 대해 간단히 알아보자

   

      + AngularJS 흐름

   


  - 개발자 가이드에서 Bootstrap, HTML Compiler, Conceptual Overview, Directives 를 꼭 읽는다 (내 포스팅에도 정리했다)

  - AngularJS 홈페이지에서 제공하는 튜토리얼 보기

  - 요약 정리 내역을 다시 보자

 


2. 프로토타입핑 해보기

  - 전체 flow를 간단히 코딩해 보자

  - egghead.io 에서 모든 동강을 따라해 본다 : 100개 넘는 강좌가 있고 짧은 대신 꼭 코딩해본다 

    

  - AngularJS 팀의 Meetup 동영상들 보기 : Angular 기능별 설명을 해준다 (이건 개당 1시간씩 넘어서 틈틈히 보자)

    + Best Practices :  미스코님이 직접 설명한다.

    

  - AngularJS에서의 Deferred and Promise에 대한 이해

    

  - http://www.yearofmoo.com/ 의 AngularJS 강좌들 코딩

    + Use AngularJS to Power

    + More AngularJS Magic

  - AngularJS Design Patterns 

  - MEAN Stack 사용 예제 : MEAN is MongoDB + Express + AngluarJS + Node.js




3. Angular 생태계

  - Angular-UI : Twitter Bootstrap, Grid 등 지속적으로 AngularJS Directives 를 만들어 내고 있다 

  - angular modules는 http://ngmodules.org/ 먼저 찾아보자

    

  - angular-strap : http://mgcrea.github.io/angular-strap/

  - Learn AngluarJS : Thinkster.io

  - AngularJS-Tips




4. 데이터 연동

  - AngularJS에서 제공하는 $resource를 사용하여 RESTful 하게 개발한다

    + 동영상에서 $resource를 어떻게 사용하는지 익히자 (GitHub Demo 소스)

    

  - RestangularJS를 이용한  RESTful 서버 연동

  - 2차원 형태의 DataSet에 대한 다양한 응용이 가능한 ReclineJS 

  

  - VisionMedia에서 만든 SuperAgent : Ajax 호출을 직관적으로 수행 with chaining

  - Reqwest로 시작해 보자 : SuperAgent와 유사 soma.js framework에서 사용함 

  - JSON store로만 사용하는 LawnChairJS 도 존재함

  - Real-time을 위한 AngularJS와 Socket.io 연동하기 seed 구성




5. 개발환경 구축하기 

  - 개발 소스 코드 저장소는 DVCS인 Git + GitHub 을 사용한다 : Git 을 통하여 성공적인 브랜칭 전략을 세우자

  - Yeoman을 통하여 AngularJS의 스케폴딩 소스를 만들어 개발한다 : AngularJS 개발환경 구성하기

  - Yeoman generator Angular 와 Express.js 연동하기




6. 참여와 공유

  - AngularJS 구글 그룹스 참여

  - 공개 그룹 활동하기

    + Facebook AgularJS 오픈 그룹 

    + Google+ AngularJS 오픈 그룹 

  - JSFiddle을 통하여 예제파일 공유하기

  - StackOverflow 통하여 Q&A 하기

  - AngularJS 트위터 팔로잉

최근 -213.10.11- 으로 AngularJS에 대한 관심이 높아지고 있고, 다양한 블로그와 관련 글이 많이 올라오고 있다. 이중 AngularJS 배우기의 종결자 블로깅을 들어가서 배워보자 



<참조>

  - 배우는 과정을 잘 요약한 블로깅 : http://blog.whydoifollow.com (강추)

  - AngularJS 내용 요약 (필독)

  - 몇가지 참조할 만한 사이트 

    + AngularJS 포스팅 in codingsmackdown.tv

       tiny -> medium -> large project 확장하는 방법 (소스)

    + 페이지 플래그먼트의 라우팅 : http://onehungrymind.com/building-a-website-with-angularjs-routes-and-partials/

    + $apply 사용 이유http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

    + $provide 사용 : http://slides.wesalvaro.com/20121113/#/

    + AngularJS에서 Dependency Injection에 대한 이해

    + 요분 유명하다 와인샐러 샘플 : http://coenraets.org/blog/2012/02/sample-application-with-angular-js

    + 전체 구성요소 설명

    + Directive 통하여 재사용가능 컴포넌트 만들기

    + Lazing Loading in AngularJS

    + Animation in AngularJS

    + AngularJS CheetSheet

  - 처음 개발할 때 8가지 유용한 개발 접근법 ($rootScope, $locationProvider 사용예)



저작자 표시 비영리 변경 금지
Posted by peter yun 윤영식
2014/06/28 19:07

ElasticSearch(이하 ES) 엔진에 수집된 데이터에 대하여 Kibana 도움 없이 직접 Data Visualization 하는 기술 스택을 알아보고, 실데이터를 통한 화면 1본을 만들어 본다. 




ES 시각화를 위한 다양한 방식의 시도들


사전조사-1) 직접 클라이언트 모듈 제작하여 Data Visualization 수행 

  - elasticsearch.js 또는 elatic.js 사용하지 않고 REST 호출 통해 데이터 시각화 수행 

    (Protovis 는 D3.js 기반 Chart를 사용함)

  - FullScale.co에서는 dangle 이라는 시각화 차트를 소개

    (D3.js 기반의 AngularJS Directives 차트)

  - D3.js 기반의 전문적인 차트를 사용하는 방법을 익힐 수 있다. 하지만 제대로 갖춰진 ES 클라이언트 모듈의 필요성 대두


사전조사-2) elasticsearch.js 사용하여 Data Visualization 수행

  - elasticsearch.js와 D3.js, jquery, require.js를 통해서 샘플 데이터를 시각화 수행

    (AngularJS는 사용하지 않고, 전문적인 차트 모듈사용하지 않음)

  - AngularJS 기반으로 Protovis 또는 Dangle 차트를 사용하여 표현해 본다.


사전조사-3) elastic.js 사용하여 Data Visualization 수행

  - elastic.js 홈페이지에서 API를 숙지한다.

  - DSL API를 살펴보자. DSL을 이해하기 위해서는 ES의 Search API에 대한 이해가 필요하다.

  - Query를 작성하고 Filtering 하면 group by having과 유사한 facets (지금은 aggregation 을 사용)하여 검색을 한다.

    Query -> Filter -> Aggregation에 대해 알면 DSL구성을 이해할 수 있다.

  - 자신의 Twitter 데이터를 가지고 elastic.js와 angular.js를 사용하여 트윗 내용을 표현하는 방법 (GitHub 소스)




ES Data Visualization을 위한 나만의 Tech Stack 만들기 


  - ES 클라이언트 모듈 : elastic.js 의 DSL(Domain Specific Language)를 숙지한다. 

    elastic.js는 ElasticSearch의 공식 클라이언트 모듈인 elasticsearch.js 의 DSL 화 모듈로 namespace는 ejs 이다.  

  - 시각화를 위한 D3.js 의 개념 이해 (D3.js 배우기)

  - Kibana에서 사용하고 있는 Frontend MV* Framework인 AngularJS (AngularJS 배우기)

  - AngularJS 생태계 도구인 yeoman 을 통해 개발 시작하기 (generator-fullstack,  Yeoman 사용방법)

  - 물론 Node.js는 기본이다. 


그래서 다음과 같이 정리해 본다. 


  - AngularJS 기반 Frontend 개발

    1) Node.js 기초

    2) Yeoman + generator-angular 기반 

  - D3.js 기반의 Chart 이며 AngularJS 바로 적용가능토록 Directives 화 되어 있는 차트 중 선택사용

    1) Protovis

    2) Dangle

    3) Angular nvd3 charts (추천)

    4) Angular-Charts

    5) Angular Google Charts 

  - elasticsearch.js를 DSL로 만든 elastic.js 사용


그래서 다시 그림으로 정리해본 기술 스택



ES Data Visualization 개발을 위한 구성 stack 그림






== 이제 만들어 봅시다!!! ==


 

환경설정

  - node.js 및 yeoman 설치 : npm install -g generator-angular-fullstack 설치 (generator-angular는 오류발생)

  - twitter bootstrap RWD 메뉴화면 구성 (기본 화면 구성)

  - angular-ui의 angular-bootstrap 설치 :  bower install angular-bootstrap --save

  - elasticsearch.js 설치 : bower install elasticsearch --save

  - elastic.js 설치 : bower install elastic.js --save

  - angular-nvd3-directives chart 설치 : bower install angularjs-nvd3-directives --save



angular layout 구성 

  - 애플리케이션 생성 : GitHub Repository를 만들어서 clone 한 디렉토리에서 수행하였다

$ git clone https://github.com/elasticsearch-kr/es-data-visualization-hackerton 

$ cd es-data-visualization-hackerton 

$ yo angular-fullstack esvisualization

  - main.html 과 scripts/controllers/main.js 를 주로 수정함 

// main.html 안에 angular-nvd3.directives html 태그 및 속성 설정 

    <div class="row">

      <div class="col-xs-12 col-md-12">

        <div class="panel panel-default">

          <div class="panel-heading">

            <button type="button" ng-click="getImpression()" class="btn btn-default">Impression Histogram</button>

          </div>


          <div class="panel-body">


            <!-- angular-nvd3-directives : multi-bar chart -->

            <div class="col-xs-12 col-md-12">

              <nvd3-multi-bar-chart

                  data="impressionData"

                  id="dataId"

                  xAxisTickFormat="xAxisTickFormatFunction()"

                  width="550"

                  height="350"

                  showXAxis="true"

                  showYAxis="true">

                    <svg></svg>

              </nvd3-multi-bar-chart>

            </div>


          </div>

        </div>

      </div>

    </div>



// main.js 안에서 elasticsearch.js를 직접 호출하여 사용함 

angular.module('esvisualizationApp')

  .controller('MainCtrl', function ($scope, $http) {


    // x축의 값을 date으로 변환하여 찍어준다 

    $scope.xAxisTickFormatFunction = function(){

      return function(d){

        return d3.time.format('%x')(new Date(d));

      }

    }


    // 화면에서 클릭을 하면 impression index 값을 ES에서 호출하여 

    // ES aggregation json 결과값을 파싱하여 차트 데이터에 맵핑한다

    $scope.getImpression = function() {


      // ES 접속을 위한 클라이언트를 생성한다 

      var client = new elasticsearch.Client({

                                              host: '54.178.125.74:9200',

                                              sniffOnStart: true,

                                              sniffInterval: 60000,

                                            });


// search 조회를 수행한다. POST 방식으로 body에 실 search query를 넣어준다 

      client.search({

          index: 'impression',

          size: 5,

          body: {

            "filter": {

                "and": [

                    {

                      "range": {

                        "time": {

                            "from": "2013-7-1", 

                            "to": "2014-6-30"

                        }

                      }

                    }

                ]

            },

            "aggs": {

              "events": {

                "terms": {

                  "field": "event"   

                },

                "aggs" : {   

                  "time_histogram" : {

                      "date_histogram" : {

                          "field" : "time",

                          "interval" : "1d",   

                          "format" : "yyyy-MM-dd" 

                      }

                  }

                }

              }

            }


            // End query.

          }

      }).then(function (resp) {

         var impressions = resp.aggregations.events.buckets[0].time_histogram.buckets;

         console.log(impressions);


         var fixData = [];

         angular.forEach(impressions, function(impression, idx) {

          fixData[idx] = [impression.key, impression.doc_count];

         });

   

   // 결과에 대해서 promise 패턴으로 받아서 angular-nvd3-directives의 데이터 구조를 만들어 준다

   // {key, values}가 하나의 series가 되고 배열을 가지면 다중 series가 된다. 

         $scope.impressionData = [

            {

              "key": "Series 1",

              "values": fixData

            }

          ];


  // apply 적용을 해주어야 차트에 데이터가 바로 반영된다.

        $scope.$apply();

      });

    }


  });




결과 화면 및 해커톤 소감

  - "Impression Histogram" 버튼을 클릭하면 차트에 표현을 한다.

  - elastic.js의 DSL을 이용하면 다양한 파라미터에 대한 핸들링을 쉽게 할 수 있을 것같다. 

  - AngularJS 생태계와 elasticsearch.js(elastic.js)를 이용하면 Kibana의 도움 없이 자신이 원하는 화면을 쉽게 만들 수 있다. 

  - 관건은 역시 ES에 어떤 데이터를 어떤 형태로 넣느냐가 가장 먼저 고민을 해야하고, 이후 분석 query를 어떻게 짤 것인가 고민이 필요!



* 헤커톤 소스 위치 : https://github.com/elasticsearch-kr/es-data-visualization-hackerton



<참조> 

  - elasticsearch.js 공식 클라이언트 모듈을 DSL로 만든 elastic.js 

  - elastic.js를 사용한 ES Data Visualization을 AngularJS기반으로 개발

  - Protovis 차트를 이용한 facet 데이터 표현

  - ElasticSearch Data Visualization 방법

  - D3.js 와 Angular.js 기반으로 Data Visualization

  - ElasticSearch의 FacetAggregation 수행 : 향후 Facet은 없어지고 Aggregation으로 대체될 것이다.

  - AngularJS Directives Chart 비교

저작자 표시 비영리 변경 금지

'ElasticSearch > Concept' 카테고리의 다른 글

[ElasticSearch] ElasticSearch의 데이터 시각화 방법  (1) 2014/06/28
Posted by peter yun 윤영식
2014/06/17 14:33

이제 모든 서비스는 모바일 먼저 기획을 하고 웹 서비스로 넘어가야 한다고 생각한다. 즉, Contents -> UX -> Design -> Develop -> Launch로 넘어가면서 그 기본은 모바일이 먼저이다. 기존에 Bootstrap을 사용했을 경우 RWD (Response Web Design)이 적용되어 해상도에 따른 사용자 경험을 데스크탑과 모바일에 준하게 줄 수 있었지만 네이티브 앱과 유사한 UX 경험을 제공하기에는 부족하다. HTML5 기반으로 개발을 한다면 RWD 외에 Mobile First 전략을 가지고 있는 하이브리드 웹앱 Framework을 살펴 볼 필요가 있다. 살펴볼 두가지의-ionic, onsenui - 하이브리드 앱(모바일 웹앱) 프레임워크는 PhoneGap + Angular.js 와 결합되는 형태를 취하고 있다. mobile angular ui는 PhoneGap과 연결시키는 별도의 작업을 수반한다. 




                       




Ionic 하이브리드 웹앱 프레임워크

  - Ionic 홈페이지

  - PhoneGap에 최적화 되어 프로젝트를 생성해 준다.

  - https://github.com/driftyco/ionic-starter-sidemenu 처럼 ionic-starter-xx의 sidemenu, tabs, blank 3가지 타입을 제고하고 있다

// 설치 

$ sudo npm install -g cordova 

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

cordova@3.5.0-0.2.4 /usr/local/lib/node_modules/cordova


$ sudo npm install -g ionic

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

ionic@1.0.14 /usr/local/lib/node_modules/ionic


// 프로젝트 생성

$ ionic start myAppSideMenu sidemenu

Running start task...

Creating Ionic app in folder /Users/prototyping/myAppSideMenu based on sidemenu project

DOWNLOADING: https://github.com/driftyco/ionic-app-base/archive/master.zip

DOWNLOADING: https://github.com/driftyco/ionic-starter-sidemenu/archive/master.zip

Initializing cordova project.

Fetching plugin "org.apache.cordova.device" via plugin registry

Fetching plugin "org.apache.cordova.console" via plugin registry

Fetching plugin "https://github.com/driftyco/ionic-plugins-keyboard" via git clone


$ cd myAppSlideMenu


  - ionic 수행

$ ionic platform add android

Running platform task...

Adding platform android

.. 생략 ..

Project successfully created.

Installing "com.ionic.keyboard" for android

Installing "org.apache.cordova.console" for android

Installing "org.apache.cordova.device" for android


$ ionic build android

Running build task...

Building platform android

Running command: /Users/prototyping/myAppSideMenu/platforms/android/cordova/build

Buildfile: /Users/prototyping/myAppSideMenu/platforms/android/build.xml

... 중략 ...

-post-build:

     [move] Moving 1 file to /Usersprototyping/myAppSideMenu/platforms/android/ant-build

     [move] Moving 1 file to /Users/prototyping/myAppSideMenu/platforms/android/CordovaLib/ant-build

debug:

BUILD SUCCESSFUL

Total time: 48 seconds


// Android의 AVD를 먼저 실행해야 한다 

$ ionic emulate android

Running emulate task...

Emulating app on platform android

Running command: /Users/nulpulum/development/studygps_company/prototyping/myAppSideMenu/platforms/android/cordova/run --emulator

... 중략 ...

BUILD SUCCESSFUL

Total time: 9 seconds

Installing app on emulator...

Using apk: /Users/prototyping/myAppSideMenu/platforms/android/ant-build/HelloCordova-debug-unaligned.apk

Launching application...

LAUNCH SUCCESS


-- AVD 통해 본 모습

  

* 안드로이드 AVD 관리하기 (참조)


 - ionic 분석

 - ionic 명령을 통하여 ionic 프레임워크와의 통합 빌드작업을 자동 수행해 준다

// 완벽하게 angular.js 기반으로 운영된다 (angular.js v1.2.12 버전 번들링)

// www/lib/ionic/js/ionic.bundle.js 


// index.html 

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">

    <title></title>


    <link href="lib/ionic/css/ionic.css" rel="stylesheet">

    <link href="css/style.css" rel="stylesheet">


    <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above

    <link href="css/ionic.app.css" rel="stylesheet">

    -->


    <!-- ionic/angularjs js -->

    <script src="lib/ionic/js/ionic.bundle.js"></script>


    <!-- cordova script (this will be a 404 during development) -->

    <script src="cordova.js"></script>


    <!-- your app's js -->

    <script src="js/app.js"></script>

    <script src="js/controllers.js"></script>

  </head>


  <body ng-app="starter">

    <ion-nav-view></ion-nav-view>

  </body>

</html>

  - ionic components



Onsen UI 프레임워크 

  - PhoneGap을 설치와 Onsen ui 설치는 별개로 진행된다. 따라서 ionic과 같이 PhoneGap에 대한 기본 지식이 필요하다  

  - Onsen ui는 angular.js directive를 제공하는데 주력한다

  - PhoneGap 환경 설정 

// PhoneGap

$ npm install -g cordova

$ cordova create MyAppOnsenui && cd MyAppOnsenui

Creating a new cordova project with name "HelloCordova" and id "io.cordova.hellocordova" at location "/Users/prototyping/MyAppOnsenui"

Downloading cordova library for www...

Download complete


$ cordova platform add android

Creating android project...

Creating Cordova project for the Android platform:

Path: platforms/android

Package: io.cordova.hellocordova

Name: HelloCordova

Android target: android-19

Copying template files...

Running: android update project --subprojects --path "platforms/android" --target android-19 --library "CordovaLib"

Resolved location of library project to: /Users/prototyping/MyAppOnsenui/platforms/android/CordovaLib

Updated and renamed default.properties to project.properties

..중략..

Project successfully created.


-- build와 emulate 전에 하기의 Onsen ui 설치와 설정을 먼저 한 후에 수행한다 


$ cordova build android

.. 중략 ..

BUILD SUCCESSFUL

Total time: 32 seconds


-- android의 AVD를 먼저 실행해야 한다 

$ cordova emulate android


  - Onsenui components : 가장 기본적인 것들을 제공함 

  - Phonegap과 Angular.js 의 결합을 개발자가 직접해야함 

  - 활발한 Community feedback이 없는 상태이다 (참조)

  - Onsenui설치

// Onsen ui

$ cd MyAppOnsenui


$ bower init  명령으로 bower.json 파일을 만들거나 기존의 generator-angular-fullstack의 것을 사용한다

bower install onsenui --save

{

  "name": "mobiconsoft-mobile-app",

  "version": "0.1.0",

  "dependencies": {

    "angular": ">=1.2.*",

    "json3": "~3.3.1",

    "es5-shim": "~3.2.0",

    "angular-resource": ">=1.2.*",

    "angular-cookies": ">=1.2.*",

    "angular-sanitize": ">=1.2.*",

    "angular-ui-router": "~0.2.10",

    "restangular": "~1.4.0",

    "jquery": "1.11.1",

    "modernizr": "~2.8.1",

    "console-shim": "*",

    "jStorage": "~0.4.8",

    "angular-gettext": "~0.2.9",

    "ladda-studygps": "~0.9.4",

    "angular-ladda-studygps": "~0.1.7",

    "onsenui": "~1.0.4"

  },

  "devDependencies": {

    "angular-mocks": ">=1.2.*",

    "angular-scenario": ">=1.2.*"

  },

  "testPath": "test/client/spec"

}


-- http://onsenui.io/OnsenUI/project_templates/sliding_menu_navigator.zip 에서 샘플 파일을 다운로드 받아서 app 폴더에 있는 것을 www 폴더로 복사한다. 그리고 index.html안에 cordova.js를 넣는다. (개발시에는 404 NOT Found 발생함)


cordova build android

cordova emulate android

-- AVD로 띄워본 결과

 


  - Sliding Menu에 있어서는 Ionic 보다는 Onsenui가 좀 더 세련되어 보임 



Mobile Angular UI

  - Slide Menu 와 기본적인 모바일 화면 구성 컴포넌트를 angular.js 기반으로 Directive화 해놓았다. 

  - 친숙한 Bootstrap 기반의 UI를 제공한다. 그러나 Twitter bootstrap의 RWD기반은 아니다



ngCordova

    

  - cordova에서 제공하는 API를 angular 에서 사용할 수 있도록 Angular Service로 만들어 놓았음



좀 더 잘 정비된 것을 쓰고 싶다면 Ionic을 기초 기술부터 체크하면 갈 것이라면 Onsenui를 추천한다. 또한 좀 더 세련되 UI는 Onsenui에 점 수를 더 주고 싶다. 그리고 서로의 아키텍쳐에 대한 부분과 커스터마이징 여부는 좀 더 들여다 보아야 할 것으로 보인다. 각각의 상황과 특성에 따라 선택하여 사용하면 될 것으로 보인다. 



<참조>

  - Ionic 시작하기 

  - onsenui 시작하기

  - onsenui sliding menu zip 

sliding_menu_navigator.zip


  - mobile angular ui

  - iSO 8 UI Framework 7

  - ngCordova

  - 용어 정의 

    

저작자 표시 비영리 변경 금지
Posted by peter yun 윤영식

티스토리 툴바