AngularJS 의 naming rule
기본적으로 AngularJS 의 이름 표기법에 익숙해지자. camelCase notation 과 hyphens notation 등을 혼용해서 사용할 수 있게 되어 있다. 예를 들면, ngHide 는 ng-hide 와 같은 이름이다.directive 이름의 의미
ui 가 어떻게 움직여라라고 이야기하는 지시자 같은 느낌으로 이름을 지은 듯 하다.어떤 식으로 사용할 것인가.
code<na-flipbox></na-flipbox>
이 때 이름(여기서는 flipbox)은 되도록 자신만의 prefix를 사용하도록 권고하고 있다. 나중에 HTML 표준에 html element 이름이 추가되는 경우를 방지하기 위해서라고 한다. [ref. 2]
어떤 모습의 widget 인가.
code<div class="flipbox"> <div class="front"> <div class="title">{{flipbox.title}}</div> <div class="description">{{flipbox.description}}</div> </div> <div class="back setting-box"> <div class="date">...</div> <div class="item">...</div> <div class="advanced-option">...</div> </div> </div>
위의 코드를 <na-flipbox> 대신에 넣어야 한다.(replace) 이러기 위해서 아래와 같이 code 를 작성하면 된다.
code
angular.module('naDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.flipbox = {
title: 'rank',
description: 'rank download'
};
}])
.directive('naFlipbox', function() {
return {
restrict: 'E',
template: 'naDirective.tpl.html'
};
});
여기서는 색칠한 부분만 고려하자. 위와 같은 code 로 <na-flipbox> 는 naDirective.tpl.html 부분의 code 로 치환된다. 당연한 이야기지만, 위에서 우리가 치환해서 넣으려 했던 html code 는 naDirective.tpl.html 에 넣어놓으면 된다.
restrict
만약 여기서 restrict : 'E' 를 생략하면 기본적으로 attribute 에만 적용하게 된다. 그래서 '치환'이 되지 않는다.attribute ? element ?
ref. 2 에서는 기존의 element 에 기능을 추가하는 것이라면 attribute 를 써서 directive 를 표시하고, 아예 하나의 component 라면 element 를 쓰라고 한다. 디자인 관점에서도 이 얘기가 맞는 듯 하다.
여러개의 $scope
- AngularJS: Developer Guide: Directives > Isolating the Scope of a Directive
- AngularJS: API: $compile > Directive Definition Object
만약 우리가 위에 만든 directive 를 다른 title, description 을 사용해서 여러번 사용하려고 한다면, $scope.flipbox 의 값을 변경하기 위해 controller 를 여러번 만들어야 한다. 왜냐하면 controller 하나에 새로운 하나의 $scope 이 만들어지기 때문이다.[ref.4]
이런 과정은 정말 별로다. 그래서 directive 에서 사용되는 $scope 을 isolating 하는 방법을 알아보자.(고립화, isolation 이라는 말은 이해가 어려울 수 있다. 단순하게 생각하면 global 변수가 아닌, local 변수를 사용하는 개념이라고 보면 좋을 듯 싶다. 또는 scope 을 argument 로 받는 개념이라고 생각하면 될 듯 하다.)
angular.module('naDirective', []) .controller('Controller', ['$scope', function($scope) { $scope.flip1 = { title: 'rank1', description: 'rank1 download' }; $scope.flip2 = { title: 'rank2', description: 'rank2 download' }; }]) .directive('naFlipbox', function() { return { restrict: 'E', scope: { flipbox: '=info' } template: 'naDirective.tpl.html' }; });
위와 같이 directive 에 scope 을 정해주면, 저것은 "flipbox 를 info 라는 attribute 에서 가져와라" 라는 뜻이 된다. 이 directive 를 위해서 사용방법도 아래처럼 수정해 주면 된다.
<div ng-controller="Controller"> <na-flipbox info="filp1"></na-flipbox> <hr> <na-flipbox info="flip2"></na-flipbox> </div>
만약에 "flipbox 를 flipbox 라는 attribute 에서 가져와라" 라고 하고 싶다면 간단히 아래처럼 써주면 된다.
scope: { flipbox: '=' }scope 에 할당할 수 있는 다른 값들(@, &, = ...)은 [ref. 6] 을 참고하자.
scope : {flipbox: '@'}flipbox 를 element 에 있는 flipbox attribute 에 설정된 값을 가져와라. DOM 의 값을 가져오므로 항상 string 이 된다. 만약 위의 경우에 '@' 를 사용하면 flipbox 는 $scope.flip1 이 아닌 "flip1" 이라는 string 을 가지게 된다.
compilation
AngularJS 에서는 compilation 과정을 통해 event listener 들을 HTML 에 붙여준다. 이 과정을 통해 page 가 interactive 하게 된다.
template 이 insert 되는 곳
보통 element 를 치환하는 경우에 element 의 child element로 template 이 들어간다. 예를 들면 이런식이다.<nae-frontbox> <div class="front"> <div class="title ng-binding"></div> <div class="description ng-binding"></div> </div> </nae-frontbox>
replace:true
만약,<nae-frontbox>
부분을 없애고 이자리에 template 이 들어가길 원한다면, replace:true 를 사용하자. 그러면 아래처럼 html 이 만들어 질 것이다.
참고로, 여기서 주의할 점은 replace 를 사용하지 않으면 directive 의 child 로 생성되기 때문에 괜찮지만 replace 를 하는 경우에는 root element 를 하나둬서 묶어야 한다. 그렇지 않으면 console 에서 error 를 보게 된다.
<div class="front"> <div class="title ng-binding"></div> <div class="description ng-binding"></div> </div> m.directive('naeFrontbox', function(){ return{ restrict: 'E', scope : false, replace: true, templateUrl : 'ui/naefrontbox.ui.tpl.html' }; });
자세한 사항은 ref. 3을 참고하자.
2개 이상의 diective
만약 내가 만든 directive 가 또 다른 directive 를 가지고 있게 하려면 어떻게 해야할까? 예를 들면 위의 flipbox 의 경우 frontbox 라는 directive 를 가지고 있게 하고 싶다.이런 경우에는 module 하나에 flipbox directive 와 front box directive 를 정의하면 된다.
단, 이 경우에 scope 이 안만들어지고 부모의 scope 이 적용된다.
간단한 ui module example
ref.5 에서 input 값에 따라 input의 style이 다르게 적용되는 예제를 볼 수 있다.ref.7 의 design pattern 이 개인적으로 마음에 든다.
간단히 여기에 ref. 7을 적용한 input 을 하나 만들었다. 이 예제는 click 시 text 가 input 창으로 변경되는 ui 이다.
naefocusinput.ui.tpl.html
<div class="focus-input"> <input type="text" name="{{ inputId }}" ng-model="ctrl.title" ng-model-options="{getterSetter : true}" ng-show="ctrl.showInput" ng-blur="ctrl.hideEditInput($event)" focus-input-on="{{ctrl.showInput}}"> <span class="title" ng-click="ctrl.showEditInput($event)" ng-hide="ctrl.showInput"> {{ctrl.title}} </span> </div>
naeFocusInput.coffee
### naeFocusInput ### m = angular.module('naeFocusInputModule', []) m.directive 'naeFocusInput', ()-> { restrict: 'E' replace: true scope: { inputId: '@' } templateUrl: 'ui/naefocusinput.ui.tpl.html' controller: 'focusInputCtrl' controllerAs: 'ctrl' } m.controller 'focusInputCtrl', ['$scope', ($scope)-> this.showInput = false this.title= 'None' this.showEditInput = ($event) -> this.showInput = true return this.hideEditInput = ($event) -> this.showInput = false return return # does not return anything, it will makes the controller not work ] m.directive 'focusInputOn', ["$timeout", ($timeout)-> { restrict: 'A' link: (scope, element, attrs)-> attrs.$observe 'focusInputOn', (newValue)-> if(newValue) $timeout ()-> el = element[0] el.focus() el.selectionStart = el.selectionEnd = el.value.length return } ]
ngIsolateScope
이 녀석이 class 에 들어있다면, local scope 가 만들어진 것이라고 보면 된다. local scope 를 위해서는 directive 에 scope 을 인자로 넣어야 한다. scope 을 전혀 정의하지 않으면 isolate scope 을 사용하지 않는 것으로 간주한다.m.directive 'naeFocusInput', ()->
{
restrict: 'E'
replace: true
scope: {}
templateUrl: 'ui/naefocusinput.ui.tpl.html'
controller: 'focusInputCtrl'
controllerAs: 'ctrl'
}
ngModel
input 과의 통신을 위해서 ngModel directive를 사용하면 된다.
See Also
- javascript - Setting focus when showing a form input in AngularJS - Stack Overflow
- AngularJS Directive Design Made Easy
- Learn AngularJS With These 5 Practical Examples
References
- Angular.js – create reusable HTML widgets with directives, By Craig Atkinson on Aug. 13 2013
- Creating Custom Directives
- replace element in angularjs directive linking function, StackOverflow
- AngularJS: Developer Guide: Controllers
- AngularJS: API: ngModel
- AngularJS: Directives
- How I've Improved My Angular Apps by Banning ng-controller
댓글 없음:
댓글 쓰기