블로그 이미지
Peter Note
Web & LLM FullStacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2013. 11. 12. 13:08 HTML5, CSS3/jQuery

jQuery UI 스타일로 작성된 내역을 AngularJS 스타일의 개발방식으로 변형하는 방법을 알아보자



1. AngularJS 길을 가다 

  - jQuery에서 UI 컴포넌트를 모아 놓은 것이 jQuery UI라면 AngularJS기반으로 UI 컴포넌트를 모아 놓은 것이 AngularJS UI 이다

    사실, Angular UI는 jQuery UI를 AngularJS를 가지고 확장한 것이다

  - jQuery UI를 통하여 DOM을 조작하여 화면을 보여주는 것과 AngularJS를 통하여 UI를 조작하는 방법은 틀리다

  - AngularJS Way를 먼저 살펴본다  

  - AngularJS를 사용하여 SoC(Separate Of Concern) 관심분리를 수행하여 테스트 및 모듈화가 가능해 진다 

    + Controller : $scope를 통한 view와 two way binding 

    + Service : view와 분리된 비즈니스 로직 구현

    + Directive : 재사용 가능 컴포넌트이며 model 값을 DOM 프러퍼티와 연결해주고, DOM 이벤트 반응하여 model 값을 업데이트한다  



2. jQuery UI Plugin 방식을 보자 

  - datepicker에 대한 사용을 본다 

<div>

    Date Of Birth:

    <input type="text" id="dateOfBirth">

    <br>

    Current user's date of birth:

    <span id="dateOfBirthDisplay"></span>

</div>

  - 자바스크립트 코드 : 비즈니스 로직과 DOM 조작이 합쳐져 있다. 날짜를 선택하면 해당 날짜의 값을 span에 표현함 


$(function () {

   var user = {

      dateOfBirth: new Date(1970, 0, 1)

   };


   var displayValue = function () {

      $("#dateOfBirthDisplay").text(new Date(user.dateOfBirth).toDateString());

   };


   var processChange = function() {

      user.dateOfBirth = $("#dateOfBirth").datepicker("getDate");

      displayValue();

   };


   $("#dateOfBirth").datepicker({

         inline: true,

         onClose: processChange,

         onSelect: processChange

      }

   );


   displayValue();


   // initial display of value in input-box

   $("#dateOfBirth").datepicker("setDate", user.dateOfBirth);


});



3. datepicker를 AngularJS 방식으로 SoC 분리해 보자

  - 위의 jQuery 방식을 angularjs 방식의 model, controller, directive로 분리해 본다 

  - AngularJS 접근법

   Step 1) Model을 먼저 생각하고 Service를 만든다

   Step 2) Model이 표현될 View에 대해 생각해 보고 template을 만들고, 필요하면 자동 모델 바인딩되는 Directive도 만든다.

   Step 3) 각 View 를 Controller에 연결한다 (ng-view and routing, ng-controller)

- Model : user.dateOfBirth

- Directive : input 태그를 my-datepicker 태그로 만든다

- Controller : $scope를 통해 model을 제어한다 

  - AngularJs 의 Step1), Step 2), Step 3) 수행

// Step 1, 3) model

function DemoController($scope) {

   $scope.user = {

      dateOfBirth: new Date(1970, 0, 1)

   }

}


// Step 2) directive in html 

<div ng-app="demo" ng-controller="DemoController">

    Date Of Birth:

    <my-datepicker type="text" ng-model="user.dateOfBirth" />

    <br>

    Current user's date of birth:

    <span id="dateOfBirthDisplay">{{user.dateOfBirth}}</span>

</div>

  


4. my-datepicker Directive 만들기 

  - AngularJS Directive 만들기에 따른 myDatepicker

    + compile 첫번째 phase : DOM 변경

    + compile 두번째 phase : DOM value 조작 

// demo 모듈에 directive 만들기 

angular.module("demo", []).directive('myDatepicker', function ($parse) {

   return {

      restrict: "E",

      replace: true,

      transclude: false,

      // compile은 최초 한번 호출되고, return 되는 펑션이 link 펑션이 된다

      compile: function (element, attrs) {

         // Phase 1 - Compile function

         // 엘러먼트의 어트리뷰트 express을 function으로 변환한다 

         // user.dateOfBirth에 대한 set, get이 가능토록 해준다 

         // attrs.ngModel === ng-model 과 같다 

         var modelAccessor = $parse(attrs.ngModel);


   // 엘러먼트 태그를 바꾸어 준다 

         var html = "<input type='text' id='" + attrs.id + "' ></input>";

         var newElem = $(html);

         element.replaceWith(newElem);


         // Phase 2 - Link function

         // - onClose, onSelect를 정의한다 

         // - 이벤트 발생시 콜백을 정의한다 

         // - 값이 변경되었을 때 Angular Context로 들어가서 watch가 불리고 최종적으로 값을 변경한다 

         return function (scope, element, attrs, controller) {


// jQuery 이벤트 콜백 펑션이 호출되면 $apply를 호출하여 Angular Context가 적용되어 $watch가 자동 호출토록 한다 

// compile, link, watch 이해하기  

            var processChange = function () {

               var date = new Date(element.datepicker("getDate"));


               // HTML element 값이 변경되었음을 $watch가 호출되도록 trigger 해주는 콜백펑션을 등록한다 

               scope.$apply(function (scope) {

                  // Change bound variable

                  modelAccessor.assign(scope, date);

               });

            };


// jQuery의 이벤트 콜백을 등록한다 

            element.datepicker({

               inline: true,

               onClose: processChange,

               onSelect: processChange

            });


// scope.$apply안엣 modelAccessor의 값이 변경되면 datepicker 의 setDate를 호출한다

            scope.$watch(modelAccessor, function (val) {

               var date = new Date(val);

               element.datepicker("setDate", date);

            });

         };

      }

   };

});



<참조>

  - 원문 : 존재하는 컴포넌트를 AngularJS의 Directives로 만들기

  - AngularJS Way

  - AngularJS Directive 만들기 

  - datepicker에서 $parse를 사용하게된 이유

posted by Peter Note