我有一个指令,这里是代码:
.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',替换:true,模板:'
在控制器范围内: {{focusinControl}}
指令范围内:
无控制对象:
假设动作按钮使用与指令相同的控制器 $scope
,只需在链接函数内的 $scope
上定义函数 updateMap
。然后,您的控制器可以在单击操作按钮时调用该函数。
<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;
};
}
scope
属性添加到指令声明中。
尽管在指令的隔离范围内公开对象以促进与它的通信可能很诱人,但这样做可能会导致混淆“意大利面条”代码,特别是如果您需要通过几个级别(控制器,指令,嵌套指令等)
我们最初沿着这条路走,但经过更多研究后发现它更有意义,并导致更易于维护和可读的代码公开事件和属性,指令将用于通过服务进行通信,然后在该服务的属性上使用 $watch指令或任何其他需要对这些更改做出反应以进行通信的控件。
这种抽象与 AngularJS 的依赖注入框架配合得非常好,因为您可以将服务注入到需要对这些事件做出反应的任何项目中。如果您查看 Angular.js 文件,您会发现其中的指令也以这种方式使用服务和 $watch,它们不会在隔离范围内公开事件。
最后,如果您需要在相互依赖的指令之间进行通信,我建议在这些指令之间共享一个控制器作为通信方式。
AngularJS's Wiki for Best Practices 还提到了这一点:
仅将 .$broadcast()、.$emit() 和 .$on() 用于在整个应用程序中全局相关的原子事件事件(例如用户身份验证或应用程序关闭)。如果您想要特定于模块、服务或小部件的事件,您应该考虑服务、指令控制器或 3rd 方库 $scope.$watch() 应该取代对事件的需求直接注入服务和调用方法对于直接通信也很有用指令是能够通过指令控制器直接相互通信
=
的变化,该变量包含方法名称和参数。 (2) 公开一个单向绑定字符串 @
作为主题 ID,并让被调用者发送关于该主题的事件。现在我看到了最佳实践维基。我认为有理由不这样做。但我仍然不是很清楚,它是如何工作的。就我而言,我创建了一个 tabset 指令,我想公开一个 switchTab(tabIndex)
方法。你能举个例子吗?
switchTab(tabIndex)
方法,只会绑定到 tabIndex
变量。您的页面控制器可能具有更改该变量的操作。您将该变量绑定/传递到您的选项卡指令中。然后,您的 tab 指令可以观察该变量的变化,并自行执行 switchTab。因为该指令根据变量决定何时/如何控制其选项卡。这不是外部资源的工作,否则外部资源需要了解指令的内部工作原理,这很糟糕。
基于 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
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();
};
});
Angular 的方法
从 Angular 的书中摘录一页关于他们如何处理的问题
<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();
};
});
$scope.foo
应该是 $scope.my_form
$scope.foo
,因为我们的模板是 <div my-directive name="foo"></div>
并且 name
属性的值是 'foo'。 <form
只是使用此技术的 angular 指令之一的示例
有点晚了,但这是一个具有隔离范围和“事件”的解决方案,可以在指令中调用函数。此解决方案的灵感来自 satchmorun 的 this SO post,并添加了一个模块和一个 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);
}
}
});
在“主”控制器中添加对 MapApi 的引用,然后调用 MapApi.updateMap() 来更新地图。
app.controller('mainController', function ($scope, MapApi) {
$scope.updateMapButtonClick = function() {
MapApi.updateMap();
};
}
您可以指定一个 DOM 属性,该属性可用于允许指令在父作用域上定义一个函数。然后,父作用域可以像其他任何方法一样调用此方法。 Here's 一个笨蛋。以下是相关代码。
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>
scope: { clearFn: '=clearfn' }
),它就会成为指令范围的一部分。
只需使用 scope.$parent 将调用的函数关联到指令函数
angular.module('myApp', [])
.controller('MyCtrl',['$scope',function($scope) {
}])
.directive('mydirective',function(){
function link(scope, el, attr){
//use scope.$parent to associate the function called to directive function
scope.$parent.myfunction = function directivefunction(parameter){
//do something
}
}
return {
link: link,
restrict: 'E'
};
});
在 HTML 中
<div ng-controller="MyCtrl">
<mydirective></mydirective>
<button ng-click="myfunction(parameter)">call()</button>
</div>
您可以将方法名称告诉指令以定义要从控制器调用但没有隔离范围的方法,
angular.module("app", []) .directive("palyer", [ function() { return { restrict: "A", template:'
点击播放按钮播放
已测试希望这对某人有所帮助。
我的简单方法(将标签视为您的原始代码)
<html>
<div ng-click="myfuncion">
<my-dir callfunction="myfunction">
</html>
<directive "my-dir">
callfunction:"=callfunction"
link : function(scope,element,attr) {
scope.callfunction = function() {
/// your code
}
}
</directive>
也许这不是最佳选择,但您可以执行 angular.element("#element").isolateScope()
或 $("#element").isolateScope()
来访问指令的范围和/或控制器。
如何在页面控制器中获取指令的控制器:
编写自定义指令以从 DOM 元素中获取对指令控制器的引用: angular.module('myApp') .directive('controller', controller);控制器.$inject = ['$parse'];函数控制器($parse){ var 指令 = { 限制:'A',链接:linkFunction };返回指令;函数链接功能(范围,el,attrs){ var directiveName = attrs.$normalize(el.prop("tagName").toLowerCase()); var directiveController = el.controller(directiveName); var 模型 = $parse(attrs.controller); model.assign(范围,directiveController);在页面控制器的 html 中使用它:
注意:给定的解决方案仅适用于元素指令的控制器(标签名称用于获取所需指令的名称)。
当您拥有“控制器作为”格式的控制器(父级和指令(隔离))时,以下解决方案将很有用
有人可能会觉得这很有用,
指令:
var directive = {
link: link,
restrict: 'E',
replace: true,
scope: {
clearFilters: '='
},
templateUrl: "/temp.html",
bindToController: true,
controller: ProjectCustomAttributesController,
controllerAs: 'vmd'
};
return directive;
function link(scope, element, attrs) {
scope.vmd.clearFilters = scope.vmd.SetFitlersToDefaultValue;
}
}
指令控制器:
function DirectiveController($location, dbConnection, uiUtility) {
vmd.SetFitlersToDefaultValue = SetFitlersToDefaultValue;
function SetFitlersToDefaultValue() {
//your logic
}
}
html代码:
<Test-directive clear-filters="vm.ClearFilters"></Test-directive>
<a class="pull-right" style="cursor: pointer" ng-click="vm.ClearFilters()"><u>Clear</u></a>
//this button is from parent controller which will call directive controller function
不定期副业成功案例分享
scope.control
存在,否则使用该指令但不需要访问该指令的方法且没有control
attr 的其他地方将开始抛出有关无法执行的错误在undefined
上设置属性