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

Publication

Category

Recent Post

2013. 11. 28. 07:08 My Projects/BI Dashboard

BI Dashboard 인 만큼 엑셀의 그리드 형태의 표현은 필수적이다. 오픈소스중에서 가장 많이 사용하고 있는 jqGrid를 Angular.js에 포팅하고 RESTful API를 호출하여 표현하는 방법을 알아보자.  




1. jqGrid 설치하기 

  - 최신버전 v4.5.4

  - jqGrid만을 MIT 라이센스하에서 사용을 할 수 있다. 

// bower 통하여 설치하기

$ bower install jqgrid --save


// index.html 에 설정하기

<!-- build:css(.tmp) styles/main.css -->

    <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">

    <link rel="stylesheet" href="bower_components/jqgrid/css/ui.jqgrid.css">

    <link rel="stylesheet" href="styles/main.css">

<!-- endbuild -->

... 중략 ...

<!-- build:js scripts/plugins.js -->

    <script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>

    <script src="bower_components/respond/respond.src.js"></script>

    <script src="bower_components/jqgrid/js/i18n/grid.locale-en.js"></script>

    <script src="bower_components/jqgrid/js/jquery.jqGrid.js"></script>

<!-- endbuild -->

  - jqgrid의 theme을 위하여 jquery-ui 의 theme을 입힌다 

// bowe 통하여 설치하기 

$ bower install jquery-ui --save


지금까지의 bower components 목록 버전 의존성

$ bower list

BIDashboard

├── angular#1.2.1 (1.2.2 available)

.. 중략 ..

│ └── angular#1.2.1

├─┬ bootstrap#3.0.2

│ └── jquery#1.9.1 (2.0.3 available)

├── console-shim#05b957a4b1

├── es5-shim#2.0.12 (latest is 2.1.0)

├── jqgrid#4.5.4

├── jquery#1.9.1 (latest is 2.0.3)

├── jquery-migrate#1.2.1

├─┬ jquery-ui#1.10.3

│ └── jquery#1.9.1 (2.0.3 available)

├── json3#3.2.5 (3.2.6 available)

├── modernizr#2.7.0

└── respond#1.3.0


// index.html 에 설정하기 

<!-- build:css(.tmp) styles/main.css -->

    <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">

    <link rel="stylesheet" href="bower_components/jquery-ui/themes/smoothness/jquery-ui.css">

    <link rel="stylesheet" href="bower_components/jqgrid/css/ui.jqgrid.css">

    <link rel="stylesheet" href="styles/main.css">

<!-- endbuild -->

... 중략 ...

<!-- build:js scripts/plugins.js -->

    <script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>

    <script src="bower_components/respond/respond.src.js"></script>

    <script src="bower_components/jquery-ui/ui/jquery-ui.js"></script>

    <script src="bower_components/jqgrid/js/i18n/grid.locale-en.js"></script>

    <script src="bower_components/jqgrid/js/jquery.jqGrid.js"></script>

<!-- endbuild -->



2. jqGrid 테스트 메뉴 추가하기 

  - 기존 프로그램에서 jqGrid 테스트 메뉴를 추가한다 

    + step-1 : views 폴더 밑으로 jqGridTest.html 파일 생성

    + step-2 : scripts 폴더 밑으로 biz 폴더 만들고 (여기선 sales) jqGridBiz.js 파일 생성 (화면 : 비즈니스모듈 = 1:1)

                   jqGridBiz.js 의 모듈 명칭, 컨트롤러 명칭을 정의한다 

    + step-3 : Main Application (DashboardApp.js) 안에 신규 Biz 모듈 설정 및 Routing 환경 설정

    + step-4 : index.html 안에 jqGridBiz.js 스크립트 태그 추가

    + step-5 : index.html 안의 메뉴설정에 jqGridTest.html이 보일 수 있도록 routing url 설정

// step-1

// views/jqGrid.html 파일 내역

jqGrid Test Page


// step-2

'use strict';

var RestTestBiz = angular.module('DasbhoardApp.JqGridBiz', ['DasbhoardApp.RestfulSvc']);

RestTestBiz.controller('JqGridBiz.salesCtrl', ['$scope', 'RestfulSvcApi', function ($scope, RestfulSvcApi) {


}]);


// step-3

// DashboardApp.js 변경 내역 

'use strict';

var DashboardApp = angular.module('DasbhoardApp', [

  'ngRoute',                                                  

  'ngCookies',

  'ngResource',

  'ngSanitize',

  'DasbhoardApp.CommonCtrl',

  'DasbhoardApp.RestTestBiz',

  'DasbhoardApp.JqGridBiz',

  'DasbhoardApp.RestfulSvc'

]);


DashboardApp.config(['$routeProvider', function ($routeProvider) {

    $routeProvider

      .when('/', {

        templateUrl: 'views/main.html'

      })

      .when('/resttest', {

        templateUrl: 'views/restTest.html',

        controller: 'RestTestBiz.personCtrl'

      })

      .when('/jqgridtest', {

        templateUrl: 'views/jqGridTest.html',

        controller: 'JqGridBiz.salesCtrl'

      })

      .otherwise({

        redirectTo: '/'

      });

  }]);


// step-4

// index.html 에 추가 

<!-- build:js scripts/dashboard-spa.js -->

    <script src="scripts/DashboardApp.js"></script>

    <script src="scripts/common/controllers/CommonCtrl.js"></script>

    <script src="scripts/common/services/RestfulSvc.js"></script>

    <script src="scripts/person/RestTestBiz.js"></script>

    <script src="scripts/sales/JqGridBiz.js"></script>

<!-- endbuild -->


// step-5

// index.html 의 메뉴 부분에 추가 

<ul class="nav navbar-nav">

<li data-ng-class="activeWhen(path()=='/')">

 <a href="" data-ng-click="setRoute('/')">Home</a>

</li>

<li data-ng-class="activeWhen(path()=='/resttest')">

 <a href="" data-ng-click="setRoute('/resttest')">RESTTest</a>

</li>

<li data-ng-class="activeWhen(path()=='/jqgridtest')">

 <a href="" data-ng-click="setRoute('/jqgridtest')">jqGridTest</a>

</li>

</ul>


// final

// 디렉토리 구조

// http://localhost:8080/#/jqgridtest  호출 결과 



3. jqGrid 의 Angular.js 적용전략 - Directive 만들기 

  - jqGridTest.html partial view html 안에 일반적인 jqGrid 표현 내역을 입력하면 화면에 아무것도 출력되지 않는다

    즉, jqGrid 사용하기 와 같은 <table> 태그와 <script> 태그를 jqGridTest.html 넣으면 화면출력이 되지 않는다는 것이다. 

    이는 Angular.js router를 통하여 partial html이 보여질 때 DOMP (DOM Parser)는 html만을 파싱하여 add 할 뿐이고, 

    <script> 태그는 수행되지 않기 때문이다 (참조)

  - jqGrid에 대한  Common Directive 만들기 : JqGridDrtv.js 

// Directive 모듈 JqGridDrtv.js 개발

'use strict';

var jqGridDrtv = angular.module('DashboardApp.JqGridDrtv', [ 'DasbhoardApp.RestfulSvc' ]);


/**

 * mc is Mobile Convergence of MobiConSoft

 * @use : <mc-jq-grid config="config" data="data"></mc-jq-grid>

 * config and data is used in Controller of Angular.js

 */

jqGridDrtv.directive('mcJqGrid', [ 'RestfulSvcApi', function(RestfulSvcApi) {

return {

restrict : 'E',

scope : {

config : '=',

data : '=',

},

link : function(scope, element, attrs) {

var table;

                         // config attribute 값의 변경을 체크하여 반영한다 

scope.$watch('config', function(newValue) {

element.children().empty();

table = angular.element('<table></table>');

element.append(table);

$(table).jqGrid(newValue);

});

                        // data attribute 값의 변경을 체크하여 반영한다 

scope.$watch('data', function(newValue, oldValue) {

var i;

for (i = oldValue.length - 1; i >= 0; i--) {

$(table).jqGrid('delRowData', i);

}

for (i = 0; i < newValue.length; i++) {

$(table).jqGrid('addRowData', i, newValue[i]);

}

});

}

};

} ]);

  - 메뉴에서 동작하도록 적용하기 

    + step-1 : Controller에 JqGridDrtv.js의 config, data attribute에 대한 샘플 데이터 설정을 한다 

    + step-2 : DashboardApp 안에 JqGridDrtv 모듈 의존관계를 설정한다

    + step-3 : index.html 안에 JqGridDrtv.js <script> 태그에 포함시킨다 

    + step-4 : jqGridTest.html 에 <mc-jq-grid> 태그를 포함시킨다 

// step-1 : JqGridBiz.js 에서 config, data 값 설정

'use strict';

var JqGridBiz = angular.module('DasbhoardApp.JqGridBiz', ['DasbhoardApp.RestfulSvc']);


JqGridBiz.controller('JqGridBiz.salesCtrl', ['$scope', 'RestfulSvcApi', function ($scope, RestfulSvcApi) {

$scope.config = {

  datatype: "local",

  height: 150,

    colNames:['Inv No','Date', 'Client', 'Amount','Tax','Total','Notes'],

    colModel:[

    {name:'id',index:'id', width:60, sorttype:"int"},

    {name:'invdate',index:'invdate', width:90, sorttype:"date"},

    {name:'name',index:'name', width:100},

    {name:'amount',index:'amount', width:80, align:"right",sorttype:"float"},

    {name:'tax',index:'tax', width:80, align:"right",sorttype:"float"},

    {name:'total',index:'total', width:80,align:"right",sorttype:"float"},

    {name:'note',index:'note', width:150, sortable:false}

    ],

    multiselect: true,

    caption: "Manipulating Array Data"

   };

   

$scope.data = [

{id:"1",invdate:"2007-10-01",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},

{id:"2",invdate:"2007-10-02",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},

{id:"3",invdate:"2007-09-01",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"},

{id:"4",invdate:"2007-10-04",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},

];

}]);


// step-2 : DashboardApp.js에서 의존성 설정

var DashboardApp = angular.module('DasbhoardApp', [

  'ngRoute',                                                  

  'ngCookies',

  'ngResource',

  'ngSanitize',

  'DasbhoardApp.CommonCtrl',

  'DashboardApp.JqGridDrtv',

  'DasbhoardApp.RestTestBiz',

  'DasbhoardApp.JqGridBiz',

  'DasbhoardApp.RestfulSvc'

]);


// step-3 : index.html 에서 <script> 태그 추가 

<!-- build:js scripts/dashboard-4.js -->

    <script src="scripts/DashboardApp.js"></script>

    <script src="scripts/common/controllers/CommonCtrl.js"></script>

    <script src="scripts/common/directives/JqGridDrtv.js"></script>

    <script src="scripts/common/services/RestfulSvc.js"></script>

    <script src="scripts/person/RestTestBiz.js"></script>

    <script src="scripts/sales/JqGridBiz.js"></script>

<!-- endbuild -->


// step-4 : jqGridTest.html 안에 <mc-jq-grid> 태그를 넣는다 

<div id="gridtest" class="container">

<div class="row">

<div class="col-md-8 alert alert-info">

<i class="icon-hand-right"></i> This is jqGrid Directive for AngularJS

</div>

</div>

<mc-jq-grid config="config" data="data"></mc-jq-grid>

</div>


// 최종결과 

// 디렉토리 구조



4. jqGrid에 Bootstrp CSS 적용하기 

  - jqGrid는 기본적으로 jquery-ui theme을 사용한다. Bootstrap으로 기본적인 Layout과 controller를 사용하면 Grid 또한 같은 사용자 경험을 주어야  한다 

  - jqGrid에 Bootstrap과 유사한 CSS 값이 적용된 화면 참조 (소스)

  - 적용 순서

    + styles/main.css 안에 jgGrid.bootstrap.css 내역을 복사하여 넣는다

    + main.css 가 맨밑에 있으므로 jqgrid의 css를 다시 쓰는 역할이다 

<!-- build:css(.tmp) styles/main.css -->

<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">

<link rel="stylesheet" href="bower_components/jquery-ui/themes/smoothness/jquery-ui.css">

<link rel="stylesheet" href="bower_components/jqgrid/css/ui.jqgrid.css">

<link rel="stylesheet" href="styles/main.css">

<!-- endbuild -->

  - 결과 

    



* jQuery UI를 Angular.js에 적용하는 방법

  - Bootstrap 스타일의 CSS를 적용했다면 그다음은 Directive로 만든 jqGrid의 column sorting을 시도해 보자 

  - column우측을 클릭하면 contents 영역에서 "loading..." 메세지만 나오고 sorting이 되지않을 것이다. 해결해 보자 

   


  - jQuery Plugins을 Directive로 만드는 이유 (참조)

// 하기와 같은 코드가 있을 경우 controller scope에서 동작을 하지 않으며, model의 변경도 반영되지 않는다

$('.datepicker').datepicker();


// 안될 경우 Angular.js 의 Directive 생성하여 동작토록 만들어야 한다

// datepicker를 wrapping한 directive 소스 

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

directives.directive('datepicker', function() {

   return function(scope, element, attrs) {

       element.datepicker({

           inline: true,

           dateFormat: 'dd.mm.yy',

           onSelect: function(dateText) {

               // input field의 jQuery Object

               var modelPath = $(this).attr('ng-model');

               // angular.js $parse와 동일한 역할

               // modelPath = a.b.c , scope = {}, dateText = 2013.11.27 이면 리턴값은 {a : { b : { c: '2013.11.27 }}} 됨

               putObject(modelPath, scope, dateText);  

               scope.$apply();

           }

       });

   }

});


// html 태그에서 datepicker attribute 로 사용한다 

<input type="text" datepicker ng-model="myobj.myvalue" />

  - Directive를 만들어주는 function의 파라미터 값의 의미

    + scope : controller가 관장하는 scope

    + element : jQuery object

    + attrs : 태그의 attribute 속성 key/value

  - datepicker의 callback function을 정의

    + onSelect : 사용자가 date을 선택했을 때 수행할 datepicker의 callback 이다 

    + $apply : 해당 controller scope에 변경값을 적용하기 위하여 scope.$apply를 호출해야 한다 (참조)

  - 데이터가 Object.properties 형태로 관리될 때 좀 더 우아하게 처리하는 방법은 $parse를 이용한다 (참조)

    + step-1 : 선택한 값은 controller의 scope안에 반영시키기 위하여 attrs.ngModel로 가져와서 $parse 파싱한다 

    + step-2 : 날짜의 값을 선택하여 해당 scope의 ngModel에 assign 반영한다 

myApp.directive('datepicker', function ($parse) {

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

        // step-1

        var ngModel = $parse(attrs.ngModel);

        $(function(){

            element.datepicker({

               ...

               onSelect:function (dateText, inst) {

                    scope.$apply(function(scope){

                        // step-2 Change binded variable

                        ngModel.assign(scope, dateText);

                    });

               }

            });

        });

    }

});

 

function MyCtrl($scope) {

    $scope.userInfo = {

        person: {

            mDate: '1967-10-07'

        }

    };  

 

 * 다른 jQuery UI 들의 Directive 소스

 * 소스 : https://github.com/ysyun/SPA_Angular_SpringFramework_Eclipse_ENV/tree/feature_jqgrid_angular

 


새로운 Directive IE8 에 적용하기

  - IE8에서는 새로운 directive를 만들어 element 태그로 사용할 경우 

  - IE8 이하일 경우 DOM을 만들어준다 (참조, 호환성가이드)

 <head>

    <!--[if lte IE 8]>

      <script>

        document.createElement('mc-jq-grid');

      </script>

    <![endif]-->

</head>



<참조>

  - Partial View html에서 javascript코드가 적용안되는 이유

  - jqGrid Directives 만들기

  - jqGrid에 Bootstrap CSS 적용하기

  - jQuery UI를 datepicker를 Angular.js Directive로 적용하기

  - jQuery UI를 Angular.js Directive로 만든 소스(GitHub) 

  - $parse를 이용하여 a.b.c 으로 시작하는 것을 json object 형태로 바꾸어주는 방법

posted by 윤영식
2013. 4. 27. 16:36 AngularJS/Concept

AngularJS에 구성 요소에 대한 Snippet을 살펴본다. 또한 jQuery와 통합하여 사용하는 방법을 알아보자 



1. 들어가기

  - Angular를 통해서 Client-Side에서 데이터와 애플리케이션 로직을 분리한다

  - 최초에 넣어야 할 라이브러리들 

<script type="text/javascript" src="/path/to/angular/angular.js"></script>

<script type="text/javascript" src="/path/to/angular/angular-resource.js"></script>



2. Module

  - 정의

    + Modules are used to fully encapsulate all the angular code of your application into one entry point

    + 컴포넌트와 같으면 Self living 할 수 있다

    + 큰 프로젝트를 할 때의 모듈 나누는 방법

  - 메인 레이아웃 파일에 다음과 코드를 넣는다

    + <html 태그에 넣거나 <body 에 넣거나 한다 

    + SPA를 한다면 아마도 <body> 태그 밑의 특정 부분이 Dynamic DOM 이 될 것이다 

<html data-ng-app="YOUR_APP_NAME">

또는

<html ng-app="YOUR_APP_NAME">


  - JavaScript에서 사용하기 

    + angular는 글로벌 변수이고, directive/controller/filter/service등을 만들기 위한 App 변수를 만들었다

    + ['ngResource']와 같이 의존하는 라이브러리를 설정한다  

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



3. Binding, Expression

  - 양방향 data binding, 조건문, 반복문

  - {{ expression }} 데이터 표현

// html

<div class="records" data-ng-repeat="record in records | orderBy:orderProp">

  <h5> {{ record.title }} </h5>

</div>


// js 

$scope.records = [{ title : 'one' }, { title : 'two' }, { title : 'three' }]; 



4. Dependency Injection

  - 코드를 조직화 하고 테스트 가능하게 만들어준다

  - controllers, module configuraitons, directives, filters, resources, routes 들을 DI 할 수 있다 

// 메소드 파라미터로 DI를 해준다

var Ctrl = function($scope, $http, $location) {

  //now you can use any of the injected variables


  //to change the URL after something has happened then you can use $location

  $location.path('/path/to/new/page');

}

//and now the injection of the variables

Ctrl.$inject = ['$scope','$http','$location'];


  - DI에 대한 개념을 제대로 잡고 싶다면 보지타님의 동영상 보라



5. Routes

  - 요청 uri path와 controller를 맵핑하는 것이다 

// 모듈의 config 에서 정의한다 

// $routeProvider 서비스를 통하여 정의한다 

// uri path에 대하여 templateUrl 과 controller를 맵핑한다 

App.config(['$routeProvider', function($routes) {


  $route.when('/',{

    templateUrl : '/templates/home.html',

    controller : HomeCtrl

  });


  $route.when('/register',{

    templateUrl : '/templates/register.html',

    controller : RegisterCtrl

  });


  $routes.otherwise({

    redirectTo : '/'

  });


}]);



6. Controller & Scope

  - 컨트롤러는 $scope와 함께하여 데이터를 연동한다 

  - controller 만들기 (ng-app의 명칭 즉, 모듈명이 없을 경우)

    + $scope.title를 변경하면 angular는 데이터 변경을 모른다 

    + 하기와 같은 예제에서는 $scope.$apply() 가 필요하다 

    + $apply() 는 일반 JavaScript Context에서 수행되는 것을 AngularJS Context로 수행 되게 해준다 (필히 참조)

    + $apply, $digest, $$phase 란 무엇인가?

// angularjs 모듈에서 파생되지 않은 컨트롤러 펑션

var SomeCtrl = function($scope, $http, $location) {

  $scope.value = 'some value';

};

// controller에게 서비스를 주입하여 준다 (DI)

SomeCtrl.$inject = ['$scope','$http','$location'];


// html에서 {{ }} 를 설정

<div class="header">{{ title }}</div>


// 하기와 같이 설정을 하면 {{ title }} 이 자동으로 바뀌어야 한다  

$scope.title = 'this is awesome';


//if a scope digestion is already going on then it will get picked up and you won't

//have to call the $scope.$apply() method

// $apply를 호출하면 $digest cycle로 들어가고 model이 변화를 감지하여 $watch 에 등록된 expression의 변경을 수행한다

// 즉, view가 re-rendering 되는 것이다 

if(!$scope.$$phase) { //this is used to prevent an overlap of scope digestion

  $scope.$apply(); //this will kickstart angular to recognize the change

}


  - $scope는 $rootScope 상속한 것이다

    + 만일 전체 애플리케이션에서 $scope를 통하여 어떤 펑션을 사용하고 싶다면 하기와 같이 한다

    + 모듈이 로딩 될 때 config 와 run 이 자동 호출된다. run은 main메소드와 유사하다 (참조

App.run(['$rootScope', function($rootScope) {

  $rootScope.sharedFunction = function() { ... };

}]);


  - controller 사용하기 정식 방법 두가지 

    + html 태그안에서 ng-controller 통하여 설정

    + $routes의 controller 설정

// html

<div data-ng-controller="SomeCtrl">...</div>


// js

$routes.when('/some/path',{

  controller : Ctrl,

  templateUrl : '/templates/controller.html'

});



7. Services

  - 전체 애플리케이션에서 공유하는 것들

  - DI를 통하여 객체를 전달함 

//define the service

// App 모듈에 myService가 정의한 서비스의 명칭

App.factory('myService', ['myOtherService', '$location', function(myOtherService, $location) {

  return function(input) {

    //do something with the input using the myOtherService or the $location objects.

    return input;

  };

}]);


//use the service within the controller

// Controller에서 $scope와 myService DI하여 공유한다 

var HomeCtrl = function($scope, myService) {

  var input = '123';

  input = myService(input);

};

HomeCtrl.$inject = ['$scope','myService'];


//use the service a directive

// App 모듈에 directive를 정의한다. myService 서비스를 DI하여 공유한다 

App.directive('myDirective', ['myService',function(myService) {

  return {

    link: function($scope, element, attrs) {

      var input = '123';

      input = myService(input);

    }

  }

}]);



8. Models

  - RESTful Web Service를 호출을 위하여 7번의 서비스 개념으로 만들어 놓고 사용할 수 있다 

// ModelName이라고 서비스를 만든다

// $resource를 통하여 서버사이드로 호출한다 

App.factory('ModelName', ['$resource', function($resource) {

  $resource.url('/path/to/model/controller/:id',{

    id : '@id', //this binds the ID of the model to the URL param

  },{

    query : { method : 'GET', isArray : true }, //this can also be called index or all

    save : { method : 'PUT' }, //this is the update method

    create : { method : 'POST' },

    destroy : { method : 'DELETE' }

  }

}]);


// Controller 에서 ModelName 서비스를 DI 받아서 호출한다

var SomeCtrl = function($scope, $http, $location, ModelName) {

  //now you can use ModelName to do your business

};

SomeCtrl.$inject = ['$scope','$http','$location','ModelName'];


  - ModelName을 통하여 다음과 같이 사용할 수 있다 (연구필요)

    + 서비스를 CRUD query 형태로 만들어서 사용한다

    + Breeze.js 로 확장할 수도 있겠다 

//list all the records on the page

var results = ModelName.query({ search : 'all' }, onSuccessFn, onFailureFn);


//get a specific record

var record = ModelName.get({ id : 123 }, onSuccessFn, onFailureFn); //onSuccessFn and onFailureFn are optional callback functions where you can further customize the response


//create a new ModelName record

var record = new ModelName();


//update that record

record.someAttr = 'someValue';

record.$save();


//or if you prefer to submit your data in a different way

ModelName.save({

    id : record.id

  },{

  somePostObject : {

    attr1 : 'value',

    attr2 : 'value2'

  }

});


//destroy the record (and include a token)

record.destroy({ token : record.token });



9. Directives

  - HTML 코드를 통하여 만들어 놓은 플러그인과 링크를 설정해 주는 것이다. 애플리케이션내에서 블럭을 격리시켜준다. (그냥 컴포넌트 개념을 생각하며 되겠다. 화면 구성을 위하여 UI 컴포넌트 추가하는 것 처럼)

  - 웹앱을 구조화하는데 도움을 준다 

  - Plugin, Validation(유효성검사), Dynamic text properties 또는 i18n, l10n 에도 활용한다 

// link 는 Controller와 Directive가 $scope 를 통하여 데이터를 공유하는 중요 통로이다 

angular.directive('myDirective',function($compile) {

  return {

    templateUrl : '/path/to/some/template.html', //(optional) the contents of this template can be downloaded and constructed into the element

    replace : true, //whether or not to replace the inner data within the element

    link : function($scope, $element, attributes) { //this is where your magic happens

      $scope.title = '...';

    }

  };

});



10. Filters

  - 필터는 재사용 가능한 오퍼레이션이다 

  - binding operation에 내장되어 함께 수행된다 예) 정렬, 문자변형, Pagination 등

// App 모듈에서 myUppercase 명칭의 filter 정의  

App.filter('myUppercase', function(data) {

  for(var i=0; i < data.length; i++) {

    data[i].title = data[i].title.toUpperCase();

  }

  return data;

});


// html에서 사용하기 

<div data-ng-repeat="for record in records | filter:myUppercase">...</div>


// 또는 javascript 코드에서 호출가능

//be sure to inject the $filter object

var values = ['one','two','three'];

values = $filter('myUppercase')(values);



11. HTML5 Mode

  - angular app이 angular의 routing system 안에서 HTML5 history방식으로 관리되게 해준다 

  - 해당 코드만 넣으면 된다 

App.config(['$locationProvider', function($location) {

  $location.html5Mode(true); //now there won't be a hashbang within URLs for browers that support HTML5 history

}]);



12. jQuery 사용

  - 가장 간단하게 angular.js 스크립트 태그 전에 jQuery 태그를 먼저 위치시키면 된다

  - Angular.js는 jqLite를 기본 사용하나 jQuery가 먼저 설정되면 jQuery로 대체되어 사용한다 



<참조>

  - 원문 : use angularjs to power your web application

  - AngularJS 소개 ppt


posted by 윤영식
2013. 3. 20. 09:36 HTML5, CSS3/jQuery

자바스크립트 코드에서 이벤트 핸들러처리가 끝난 후 preventDefault() 와 return false 등의 코드를 본적이 있을 것이다. 간혹 stopPropagation() 호출도 보이는데 이들의 차이점을 알아보자 



1) preventDefault vs return false, stopPropagation : jQuery를 사용하지 않은 경우 

  - stopPropagation 은 사용자 정의 이벤트의 bubbling up 되는 것을 막아준다 

    + 이벤트와 이벤트 핸들러를 찾기 위한 캡쳐링과 버블링에 대해 이곳을 참조한다.

    + 사용자 정의 이벤트는 개발자가 직접 이벤트 핸들러를 작성할 경우

    + 즉, 사용자가 작성한 이벤트 핸들러의 동작을 막아준다

  - preventDefault 는 기본 정의 이벤트의 동작을 막아준다 

    + <a href..> 앵커 태그와 같은 기본 제공 이벤트 (사이트로 이동하는 것) 

    + 즉, 기본 이벤트의 동작을 막아준다 

  - return false 는 jQuery 사용할 때와 안할 때의 반응이 틀리다

    + jQuery 사용안할 때는 preventDefault와 동일하게 동작한다 

  

  - 주석 a, b, c 케이스 테스트 : 화면의 "[Click me]" 레이블을 클릭할 경우

 

<html>

<body>

<a href="http://mobicon.tistory.com">

<div id="div1">

<input type="label" id="label1" value="[Click me]"/>

</div>

</a>


<script>

document.getElementById('div1').onclick = function() { 

alert('click div1'); 

};

document.getElementById('label1').onclick = function(e) { 

alert('click label1'); 

// a 

//e.stopPropagation();

// b

//e.preventDefault();

// c

//return false;

};

</script>

</body>

</html>


   + e.stopPropagation() 만 주석 제거

      "click label1" 경고창 뜨고 "mobicon.tistory.com" 사이트로 이동 ("click div1" 경고창 안뜸. 즉, 버블링 업 막아줌)

   + e.preventDefault() 만 주석 제거

      "click label1" 경고창 뜨고 "click div1" 경고창 뜸 그러나 "mobicon.tistory.com"으로 이동하지 않음 (즉, 기본 이벤트 막아줌)

   + return false 만 주석 제거

      "click label1" 경고창 뜨고 "click div1" 경고창 뜸 그러나 "mobicon.tistory.com"으로 이동하지 않음 (즉, 기본 이벤트 막아줌)


  - jQuery를 사용하지 않은 e.preventDefault와 return false 의 동작은 동일하다



2) preventDefault vs return false, stopPropagation : jQuery를 사용할 경우 

  - stopPropagation 상동

  - preventDefault 상동

  - return false 는 jQuery 사용할 때와 안할 때의 반응이 틀리다

    + jQuery 사용할 때는 preventDefault와 동일하게 동작한다 

<html>

<body>

<a href="http://mobicon.tistory.com">

<div id="div1">

<input type="label" id="label1" value="[Click me]"/>

</div>

</a>


<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>

<script>

$('#div1').click( function() { 

alert('click div1'); 

} );

$('#label1').click( function(e) { 

alert('click label1'); 

//e.stopPropagation();

//e.preventDefault();

//return false;

} );

</script>

</body>

</html>

   

   + e.stopPropagation() 만 주석 제거

      상동

   + e.preventDefault() 만 주석 제거

      상동

   + return false 만 주석 제거

      "click label1" 경고창 뜨고 "click div1" 경고창은 안 뜸 그리고 "mobicon.tistory.com"으로 이동하지 않음 


  - 결론적으로 jQuery를 사용하여 return false를 쓸 경우 stopPropgation() 와 preventDefault() 가 동시에 적용됨 



<참조>

  - stopPropagation()과 preventDefault() 차이

  - preventDefault() vs return false 차이

  - 자바스크립트 이벤트 핸들링

posted by 윤영식
prev 1 next