지시어가 있습니다. 코드는 다음과 같습니다.
.directive('map', function() {
return {
restrict: 'E',
replace: true,
template: '<div></div>',
link: function($scope, element, attrs) {
var center = new google.maps.LatLng(50.1, 14.4);
$scope.map_options = {
zoom: 14,
center: center,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// create map
var map = new google.maps.Map(document.getElementById(attrs.id), $scope.map_options);
var dirService= new google.maps.DirectionsService();
var dirRenderer= new google.maps.DirectionsRenderer()
var showDirections = function(dirResult, dirStatus) {
if (dirStatus != google.maps.DirectionsStatus.OK) {
alert('Directions failed: ' + dirStatus);
return;
}
// Show directions
dirRenderer.setMap(map);
//$scope.dirRenderer.setPanel(Demo.dirContainer);
dirRenderer.setDirections(dirResult);
};
// Watch
var updateMap = function(){
dirService.route($scope.dirRequest, showDirections);
};
$scope.$watch('dirRequest.origin', updateMap);
google.maps.event.addListener(map, 'zoom_changed', function() {
$scope.map_options.zoom = map.getZoom();
});
dirService.route($scope.dirRequest, showDirections);
}
}
})
updateMap()
사용자 조치 를 요청 하고 싶습니다 . 조치 단추가 지시문에 없습니다.
updateMap()
컨트롤러에서 전화하는 가장 좋은 방법은 무엇입니까 ?
답변
분리 된 범위를 사용 =
하려면 컨트롤러 범위에서 변수의 양방향 바인딩 을 사용하여 제어 개체를 전달할 수 있습니다 . 동일한 제어 오브젝트를 사용하여 페이지에서 동일한 지시문의 여러 인스턴스를 제어 할 수도 있습니다.
angular.module('directiveControlDemo', [])
.controller('MainCtrl', function($scope) {
$scope.focusinControl = {};
})
.directive('focusin', function factory() {
return {
restrict: 'E',
replace: true,
template: '<div>A:{{internalControl}}</div>',
scope: {
control: '='
},
link: function(scope, element, attrs) {
scope.internalControl = scope.control || {};
scope.internalControl.takenTablets = 0;
scope.internalControl.takeTablet = function() {
scope.internalControl.takenTablets += 1;
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="directiveControlDemo">
<div ng-controller="MainCtrl">
<button ng-click="focusinControl.takeTablet()">Call directive function</button>
<p>
<b>In controller scope:</b>
{{focusinControl}}
</p>
<p>
<b>In directive scope:</b>
<focusin control="focusinControl"></focusin>
</p>
<p>
<b>Without control object:</b>
<focusin></focusin>
</p>
</div>
</div>
답변
동작 버튼 $scope
이 지시어 와 동일한 컨트롤러 를 사용한다고 가정하면 링크 기능 내부에 기능 updateMap
을 정의 $scope
하십시오. 그런 다음 컨트롤러는 작업 버튼을 클릭하면 해당 기능을 호출 할 수 있습니다.
<div ng-controller="MyCtrl">
<map></map>
<button ng-click="updateMap()">call updateMap()</button>
</div>
app.directive('map', function() {
return {
restrict: 'E',
replace: true,
template: '<div></div>',
link: function($scope, element, attrs) {
$scope.updateMap = function() {
alert('inside updateMap()');
}
}
}
});
@FlorianF의 의견에 따라 지시문이 고립 된 범위를 사용하면 상황이 더 복잡합니다. 그것을 작동시키는 한 가지 방법이 있습니다 : 지시어 기능을 컨트롤러에 등록 할 지시어에 set-fn
속성을 추가하십시오 map
:
<map set-fn="setDirectiveFn(theDirFn)"></map>
<button ng-click="directiveFn()">call directive function</button>
scope: { setFn: '&' },
link: function(scope, element, attrs) {
scope.updateMap = function() {
alert('inside updateMap()');
}
scope.setFn({theDirFn: scope.updateMap});
}
function MyCtrl($scope) {
$scope.setDirectiveFn = function(directiveFn) {
$scope.directiveFn = directiveFn;
};
}
답변
의사 소통의 격리 된 범위에서 개체와의 통신을 용이하게하려는 유혹이있을 수 있지만, 이렇게하면 “스파게티”코드가 혼동 될 수 있습니다. 특히이 통신을 몇 가지 수준 (제어기, 명령, 중첩 지시문 등)
우리는 원래이 길을 갔지만, 더 많은 연구 결과에 따르면, 지시어가 서비스를 통한 통신에 사용하고 그 서비스의 속성에 $ watch를 사용하여 이벤트와 속성을 노출하는 것이 더 이해하기 쉽고 코드를 유지하고 읽기 쉽다는 것을 발견했습니다. 의사 소통을 위해 이러한 변경 사항에 대응해야하는 지침 또는 기타 통제.
이 추상화는 AngularJS의 의존성 주입 프레임 워크와 매우 잘 작동하므로 해당 이벤트에 반응 해야하는 모든 항목에 서비스를 주입 할 수 있습니다. Angular.js 파일을 보면이 방식의 지시문도 이러한 방식으로 서비스와 $ watch를 사용한다는 것을 알 수 있으며 격리 된 범위에서 이벤트를 노출하지 않습니다.
마지막으로, 서로 종속 된 지시문간에 통신해야하는 경우, 통신 수단으로 해당 지시문간에 컨트롤러를 공유하는 것이 좋습니다.
AngularJS의 Wiki for Best Practices 도 다음과 같이 언급합니다.
원자 적 이벤트에는. $ broadcast (),. $ emit () 및. $ on () 만 사용하십시오. 전체 앱에서 전 세계적으로 관련된 이벤트 (예 : 사용자 인증 또는 앱 종료). 모듈, 서비스 또는 위젯 관련 이벤트를 원하는 경우 서비스, 지시문 컨트롤러 또는 타사 라이브러리를 고려해야합니다.
- $ scope. $ watch ()는 이벤트의 필요성을 대체해야합니다
- 서비스를 직접 주입하고 메소드를 호출하는 것도 직접적인 의사 소통에 유용합니다
- 지시문은 지시문 컨트롤러를 통해 서로 직접 통신 할 수 있습니다.
답변
Oliver의 대답을 바탕으로-지시문의 내부 메소드에 항상 액세스 할 필요는 없으며, 이러한 경우 control
오류가 발생하지 않도록 빈 객체를 작성 하고 지시문에 attr을 추가하지 않아도됩니다 ( cannot set property 'takeTablet' of undefined
).
지시문 내의 다른 위치에서이 방법을 사용할 수도 있습니다.
scope.control
존재 하는지 확인 하고 공개 모듈 패턴과 유사한 방식으로 메소드를 설정합니다.
app.directive('focusin', function factory() {
return {
restrict: 'E',
replace: true,
template: '<div>A:{{control}}</div>',
scope: {
control: '='
},
link : function (scope, element, attrs) {
var takenTablets = 0;
var takeTablet = function() {
takenTablets += 1;
}
if (scope.control) {
scope.control = {
takeTablet: takeTablet
};
}
}
};
});
답변
솔직히 말해서, 나는이 스레드에서 어떤 대답도 확신하지 못했습니다. 그래서, 여기 내 해결책이 있습니다 :
지시문 처리기 (관리자) 접근
이 방법은 지시어 $scope
가 공유 된 것인지 분리 된 것인지 아닌지에 관계없이
factory
지시문 인스턴스를 등록하는 A
angular.module('myModule').factory('MyDirectiveHandler', function() {
var instance_map = {};
var service = {
registerDirective: registerDirective,
getDirective: getDirective,
deregisterDirective: deregisterDirective
};
return service;
function registerDirective(name, ctrl) {
instance_map[name] = ctrl;
}
function getDirective(name) {
return instance_map[name];
}
function deregisterDirective(name) {
instance_map[name] = null;
}
});
지시문 코드는 일반적으로 지시문 컨트롤러 내부에 DOM을 다루지 않는 모든 논리를 넣습니다. 그리고 핸들러 내부에 컨트롤러 인스턴스를 등록
angular.module('myModule').directive('myDirective', function(MyDirectiveHandler) {
var directive = {
link: link,
controller: controller
};
return directive;
function link() {
//link fn code
}
function controller($scope, $attrs) {
var name = $attrs.name;
this.updateMap = function() {
//some code
};
MyDirectiveHandler.registerDirective(name, this);
$scope.$on('destroy', function() {
MyDirectiveHandler.deregisterDirective(name);
});
}
})
템플릿 코드
<div my-directive name="foo"></div>
factory
공개적으로 노출 된 메소드를 실행하고 실행 하여 컨트롤러 인스턴스에 액세스
angular.module('myModule').controller('MyController', function(MyDirectiveHandler, $scope) {
$scope.someFn = function() {
MyDirectiveHandler.get('foo').updateMap();
};
});
각도의 접근
그들이 다루는 방법에 대한 앵귤러의 책에서 잎을 가져 오기
<form name="my_form"></form>
$ parse를 사용 하고 $parent
범위에서 컨트롤러를 등록하십시오 . 이 기법은 분리 된 $scope
지시문 에서는 작동하지 않습니다 .
angular.module('myModule').directive('myDirective', function($parse) {
var directive = {
link: link,
controller: controller,
scope: true
};
return directive;
function link() {
//link fn code
}
function controller($scope, $attrs) {
$parse($attrs.name).assign($scope.$parent, this);
this.updateMap = function() {
//some code
};
}
})
다음을 사용하여 컨트롤러 내부에 액세스하십시오. $scope.foo
angular.module('myModule').controller('MyController', function($scope) {
$scope.someFn = function() {
$scope.foo.updateMap();
};
});
답변
조금 늦었지만 이것은 지시문에서 함수를 호출하는 격리 된 범위와 “이벤트”가있는 솔루션입니다. 이 솔루션은 영감 이 SO 게시물 에 의해 satchmorun 과 모듈과 API를 추가합니다.
//Create module
var MapModule = angular.module('MapModule', []);
//Load dependency dynamically
angular.module('app').requires.push('MapModule');
지시문과 통신 할 API를 작성하십시오. addUpdateEvent는 이벤트를 이벤트 배열에 추가하고 updateMap은 모든 이벤트 함수를 호출합니다.
MapModule.factory('MapApi', function () {
return {
events: [],
addUpdateEvent: function (func) {
this.events.push(func);
},
updateMap: function () {
this.events.forEach(function (func) {
func.call();
});
}
}
});
이벤트를 제거하려면 기능을 추가해야 할 수도 있습니다.
지시문에서 MapAPI에 대한 참조를 설정하고 MapApi.updateMap이 호출 될 때 $ scope.updateMap을 이벤트로 추가하십시오.
app.directive('map', function () {
return {
restrict: 'E',
scope: {},
templateUrl: '....',
controller: function ($scope, $http, $attrs, MapApi) {
$scope.api = MapApi;
$scope.updateMap = function () {
//Update the map
};
//Add event
$scope.api.addUpdateEvent($scope.updateMap);
}
}
});
“main”컨트롤러에서 MapApi에 대한 참조를 추가하고 MapApi.updateMap ()을 호출하여 맵을 업데이트하십시오.
app.controller('mainController', function ($scope, MapApi) {
$scope.updateMapButtonClick = function() {
MapApi.updateMap();
};
}
답변
지시문이 상위 범위에서 함수를 정의하도록 허용하는 데 사용할 수있는 DOM 속성을 지정할 수 있습니다. 그러면 상위 범위는 다른 방법과 같이이 메소드를 호출 할 수 있습니다. 여기 plunker은. 아래는 관련 코드입니다.
clearfn
부모 범위가 범위 속성을 전달하여 지시문이 원하는 동작을 수행하는 함수로 설정할 수있는 지시문 요소의 속성입니다.
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<script data-require="angular.js@*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<style>
my-box{
display:block;
border:solid 1px #aaa;
min-width:50px;
min-height:50px;
padding:.5em;
margin:1em;
outline:0px;
box-shadow:inset 0px 0px .4em #aaa;
}
</style>
</head>
<body ng-controller="mycontroller">
<h1>Call method on directive</h1>
<button ng-click="clear()">Clear</button>
<my-box clearfn="clear" contentEditable=true></my-box>
<script>
var app = angular.module('myapp', []);
app.controller('mycontroller', function($scope){
});
app.directive('myBox', function(){
return {
restrict: 'E',
scope: {
clearFn: '=clearfn'
},
template: '',
link: function(scope, element, attrs){
element.html('Hello World!');
scope.clearFn = function(){
element.html('');
};
}
}
});
</script>
</body>
</html>