Angular 환경의 Jquery 사용(Jquery 플러그인)
#
Find similar titles
- 최초 작성자
- 최근 업데이트
Structured data
- Category
- Programming
Table of Contents
Angular 환경의 jQuery 사용(jQuery 플러그인) #
jQuery 플러그인 #
jQuery는 많은 사람이 사용하기 때문에 그에 맞는 플러그인이 계속 제공되고 있다.
홈페이지에 원하는 기능을 구현하려고 할 때 jQuery 플러그인으로 쉽게 사용할 수 있고
자신만의 플러그인 제작도 가능하다.
$(document).ready(function() {
$('#slider').slider({
slide: function(event, ui) {
$('#slider-value').text(ui.value);
}
});
});
주요 내용 #
- Directive 내 link 함수에서 jQuery와 연동을 할 수 있다.
- jQuery로 scope 데이터를 변경하는 경우 자동으로 바인딩 되지 않는다. ( scope.$apply() 호출이 필요 )
- 데이터 변경 시 jQuery 쪽으로 호출하는 것도 자동으로 되지 않으므로 scope.$watch()로 지켜보아야 한다.
사용 #
1. Directive 만들기 #
jQuery 플러그인 코드를 재사용하기 위해 플러그인에 대한 directive를 작성할 수 있다. directive는 compile()과 link()로 분리할 수 있는데 compile()은 AngularJS의 template를 변환하는 용도로 사용되고 link()는 model과 view 간의 동적인 연결을 담당한다. 그러므로 모든 플러그인 초기화 코드는 directive의 link 메소드에 있어야 한다.
-
Directive 특징
- Camel cased name을 가진다. ex) userId
- 변환될 때는 Snake case(-)로 변경된다. ex) user-id
-
지시자는 Element name, Attribute, Class name, Comment에 올 수 있다.
1. Element name : <div test-directive></div> 2. Attribute : <test-directive></test-directive> 3. Class name : <div class="test-directive"></div> 4. Comment : <!-- directive : test-directive -->
-
directive는 compile function과 link function으로 나뉜다.
1. Compile Function : 지시자에 따라 template DOM(the Document Object Model, 문서 객체 모델) element를 변환하여 특별한 DOM Element를 만들어 준다. 2. Link Function : 지시자가 복제된 DOM Element에 listener를 등록하도록 해준다.
-
HTML에서 Directive가 이루어지는 과정
- 최초의 Angular의 template는 HTML이므로 표준 브라우저 API를 사용하여 DOM으로 파싱된다.
- $compile 메소드를 통해 DOM을 해석하면서 지시자(directive)를 찾는다. 지시자는 $compile() function이 수행되면서 DOM 구조를 변경하고 응답을 위하여 link() function으로 return 한다.
-
지시자별로 link()를 호출하여 지시자별 listener 등록과 scope에 대한 watch를 설정한다. 이에 따라 scope와 DOM 사이에 live binding이 되는 것이다.
var $compile = ...; var scope = ...; var html = '<div ng-bind="exp"></div>'; // Step 1 : parse HTML into DOM element var template = angular.element(html); // Step 2 : compile the template var linkFn = $compile(template); // Step 3 : link the compiled template with the scope. linkFn(scope);
-
Directive 내부 구성
- name : 현재 scope의 명칭 (optional)
- priority : copmpile function의 호출 우선순위를 지정한다.
-
scope : true이면 새로운 scope 객체를 생성하고 부모 scope 객체를 상속하고, false면 새로운 scope 객체를 생성하지 않고 부모가 가진 같은 scope 객체를 공유한다. {} 새로운 격리된 scope 생성으로 부모 scope 상속이 없다. 새로운 컴포넌트 만들 때 유용하다.
-
{}로 만들 때 안의 내용
@ : directive의 attribute value를 {{ }}방식 (interpolation)을 이용해 부모 scope에 접근 = : 부모 scope의 property와 directive의 property를 data binding 하여 부모 scope에 접근 & : parent scope에서 execute expression 방법을 제공
-
-
controller : pre-linking 전에 호출되어서 지시자들끼리 공유를 하려고 할 때 사용
- require : 다른 controller에 현재 지시자의 linking functon을 전달할 때 사용
-
restrict 속성을 추가하면 일부 메소드에서만 지시문을 호출하도록 제한할 수 있다. 이때 restrict의 값은 E (Element name), A (Attribute), C (Class name), M (Comment)가 올 수 있다.
<test-directive></test-directive> <div test-directive></div> <script> var app = angular.module("myApp", []); app.directive("testDirective", function() { return { restrict : "A", template : "<h1>Made by a directive!</h1>" }; }); </script>
-
template : HTML file
- templateUrl : 로딩할 URL 지정
- replace : true이면 현재 Element를 append가 아닌 replace 한다.
- transclude : ngTransclued Element로 컴파일 및 지시자로 쓰임
- compile : compile function 정의
- link : link function 정의
-
Directive 만들기
-
전체 내역
myModule.directive('directiveName', function factory(injectables) { var directiveDefinitionObject = { priority: 0, template: '<div></div>', templateUrl: 'directive.html', replace: false, transclude: false, restrict: 'A', scope: false, 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) { ... } }; return directiveDefinitionObject; });
-
기본 내역 : 없는 것은 기본값을 사용한다.
app.directive('ngSliderOne', [function() { return { restrict: 'A', scope: { 'model': '=' }, link: function(scope, elem, attrs) { var $slider = $(elem); $slider.slider({ value: +scope.model, slide: function(event, ui) { scope.$apply(function() { scope.model = ui.value; }); } }); } }; }]);
-
2. Angular App 안에서 jQuery 플러그인 #
Angular App 안에서 jQuery 플러그인을 사용하게 되면 Angular가 플러그인의 변경사항이나 상호작용을 인식하지 못하여 플러그인의 데이터 바인딩이 되지 않는다.
<div ng-app="MyApp">
<div ng-controller="AppCtrl">
<div id="ng-slider"></div>
<p>The slider's value is: </p>
</div>
</div>
var app = angular.module('MyApp', []);
app.controller('AppCtrl', ['$scope', function($scope) {
$scope.sliderValue = 0;
// This slider won't work. Something's missing...
$('#ng-slider').slider({
slide: function(event, ui) {
$scope.sliderValue = ui.value;
}
});
}]);
$scope.$apply() #
Angular는 일반 객체를 그대로 사용할 수 있다는 점과 데이터를 원할 때 언제든지 업데이트할 수 있다는 점, 값의 변경이 우리가 설정한 바인딩 객체 안에서 이루어진다는 이점을 가지고 있는데 이 방법이 잘 작동하기 위해서는 데이터가 변경되는 시점이 언제인지 알아야 한다. 이때 $scope.$apply()를 사용하여 끊어진 데이터 바인딩을 복원할 수 있다.
-
다음은 setTimeout()를 사용하여, 약간의 delay 후 새로운 턴 안에서 함수를 실행하고 있다.
function Ctrl($scope) { $scope.message = "Waiting 2000ms for update"; setTimeout(function () { $scope.message = "Timeout called!"; // AngularJS unaware of update to $scope }, 2000); }
위의 예제에는 Angular가 새로운 순서에 대해서 알지 못하기 때문에, $scope 변경이 화면에 반영되지 않는다. Angular가 변경을 감지하지 못했기 때문인데 우리가 $scope.$apply()로 코드를 감싼다면, $scope 변경을 Angular가 감지하여 화면을 업데이트한다.
-
$scope.$apply()를 사용하여 끊어진 데이터 바인딩을 복원한다.
function Ctrl($scope) { $scope.message = "Waiting 2000ms for update"; setTimeout(function () { $scope.$apply(function () { // wrapping using $scope.$apply $scope.message = "Timeout called!"; }); }, 2000); }
-
$scope.$apply() VS $scope.$apply(fn)
$apply 함수를 호출할 때 인수 없이 호출하는 경우와 함수 인수를 넘기고 호출하는 때도 있다. 만약 코드를 함수로 감싸지 않고 $apply 함수에 넘겨주었다면 코드에서 에러가 발생했을 때 그 에러는 Angular의 외부로 던져지게 된다. 즉, application 내부에서 사용하는 에러 처리 메커니즘이 코드가 만들어낸 에러를 발견하지 못한다는 뜻이다. $apply()는 코드를 실행할 뿐 아니라 try/catch문 안에서 실행해주기 때문에 코드에서 발생하는 에러는 항상 Angular에게 잡힌다. -
$scope.apply()안에서 jQuery 플러그인 사용하기
$scope.apply() 안에서 실행함으로써 application이 jQuery 플러그인에서 변경한 사항을 모든 $scope 속성에 알린다.var app = angular.module('MyApp', []); app.controller('AppCtrl', ['$scope', function($scope) { $scope.sliderValue = 0; // This slider WILL work $('#ng-slider').slider({ slide: function(event, ui) { // Tell Angular you're updating a value $scope.apply(function() { $scope.sliderValue = ui.value; }); } }); }]);
Directive 만들기 #
jQuery 플러그인 코드를 더 재사용하기 위해 플러그인에 대한 directive를 작성할 수 있다. 모든 플러그인 초기화 코드는 directive의 link메소드에 있어야 한다.
<div ng-app="MyApp">
<div ng-controller="AppCtrl">
<div jq-slider model="sliderValue"></div>
<p>The slider's value is: <input ng-model="sliderValue"/></p>
</div>
</div>
var app = angular.module('MyApp', []);
app.controller('AppCtrl', ['$scope', function($scope) {
$scope.sliderValue = 50;
}]);
app.directive('jqSlider', [function() {
return {
restrict: 'A',
scope: {
'model': '='
},
link: function(scope, elem, attrs) {
$(elem).slider({
value: +scope.model,
slide: function(event, ui) {
$scope.apply(function() {
scope.model = ui.value;
});
}
});
}
};
}]);
양방향 데이터 추가 ($scope.$watch()) #
$scope.$apply()를 사용하면 jQuery 플러그인에서 model로의 단방향 데이터 바인딩 만을 제공한다. Angular에서는 $scope.$watch()를 사용하여 특정 구문에 리스너를 바인딩하여 model의 변경사항을 볼 수 있다. $watch() 메소드에 검사 할 부분을 알려주고, AngularJS는 검사 중인 항목이 변경될 때마다 청취자를 호출한다.
-
$scope.$watch()
scope 객체 안에 존재하는 메서드로, 이름처럼 특정 변수를 주시하면서 값의 변화가 있는지를 점검하고 변화가 있으면 미리 등록해놓은 콜백 메서드를 호출하게 된다.$scope.$watch('name', function(newValue, oldValue){ window.alert('$scope.name의 값이 '+ $scope['name']+ '로 바뀌었다.'); }, true);
- 첫 번째 파라미터 'name'은 scope 상의 model 이름이다. ($scope.name)
여러개 인자는; 로 구분한다. - 두 번째 파라미터는 값이 변했을 때 수행하게 될 콜백 메서드이다.
- 마지막 파라미터는 true, false로 보통은 값의 변화를 레퍼런스의 변화로 인지하게 된다.
기본값인 false에서는 관찰하고 있는 변수의 레퍼런스가 변화했는지 체크하게 되고, true일 경우 레퍼런스가 아닌 실제 변수내의 값이 변화했는지를 점검하게 된다.
- 첫 번째 파라미터 'name'은 scope 상의 model 이름이다. ($scope.name)
-
$scope.$watch()로 양방향 데이터 추가
model이 다른 입력에서 변경될 때 플러그인을 업데이트하려면 $scope.$watch()를 사용하여 값에 대한 변경사항을 Angular로 보고 이러한 변경 사항을 반영하도록 지시문을 업데이트해야 한다.var app = angular.module('MyApp', []); app.controller('AppCtrl', ['$scope', function($scope) { $scope.sliderValue = 50; }]); app.directive('jqSlider', [function() { return { restrict: 'A', scope: { 'model': '=' }, link: function(scope, elem, attrs) { $(elem).slider({ value: +scope.model, slide: function(event, ui) { $scope.apply(function() { scope.model = ui.value; }); } }); // Watch for changes to the model and update the slider scope.$watch('model', function(newVal) { $slider.slider('value', newVal); }); } }; }]);