Javascript 从 AngularJS 中的父控制器调用指令的方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28116680/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calling directive's methods from parent controller in AngularJS
提问by ianaya89
I am using AngularJSwith the alias controllers pattern. I can't access (or I don't know how to) directive methods from a parent controller.
我将AngularJS与别名控制器模式一起使用。我无法从父控制器访问(或我不知道如何访问)指令方法。
I have a function inside my controller that should call a directive method but this directive method is not available inside the thiscontroller value.
我的控制器中有一个函数应该调用一个指令方法,但是这个指令方法在this控制器值中不可用。
This is what I have. What I am doing wrong?
这就是我所拥有的。我做错了什么?
JS
JS
angular.module('myApp', []).
controller('MyCtrl', function(){
this.text = 'Controller text';
this.dirText = 'Directive text';
this.click = function(){
this.changeText();
}
})
.directive('myDir', function(){
return {
restrict: 'E',
scope: {
text: '='
},
link: function(scope, element, attrs){
scope.changeText = function(){
scope.text = 'New directive text';
};
},
template: '<h2>{{text}}</h2>'
};
});
HTML
HTML
<div ng-app="myApp">
<div ng-controller="MyCtrl as ctrl">
<h1>{{ctrl.text}}</h1>
<my-dir text="ctrl.dirText"></my-dir>
<button ng-click="ctrl.click()">Change Directive Text</button>
</div>
</div>
Herea codepen with the code.
这里有一个带有代码的代码笔。
回答by Pankaj Parkar
If you strictly want to use isolated scopeinside a directive then the directive method can be only called by using angular events such as $broadcast& $emit
如果您严格想scope在指令内使用隔离,则只能通过使用诸如$broadcast& 之类的角度事件来调用指令方法$emit
In your case, you need to use $broadcastto send event to entire $rootScope
在您的情况下,您需要使用$broadcast将事件发送到整个$rootScope
You Code will become like this.
你的Code就会变成这个样子。
HTML
HTML
<div ng-app="myApp">
<div ng-controller="MyCtrl as ctrl">
<h1>{{ctrl.text}}</h1>
<my-dir text="ctrl.dirText"></my-dir>
<button ng-click="ctrl.click()">Change Directive Text</button>
</div>
</div>
CODE
代码
angular.module('myApp', []).
controller('MyCtrl', function($rootScope){
var that = this;
this.text = 'Controller text';
this.dirText = 'Directive text';
this.click = function(){
$rootScope.$broadcast('changeText',{});
}
}).
directive('myDir', function(){
return {
restrict: 'E',
scope: {
text: '='
},
link: function(scope, element, attrs){
scope.changeText = function(){
scope.text = 'New directive text';
};
scope.$on('changeText',function(event, data){
scope.changeText()
});
},
template: '<h2>{{text}}</h2>'
};
});
Instead of calling method of child scope, you need to broadcast an event and that will have to be listened by the directive scope & it will fire changeTextmethod after listening to that event.
您需要广播一个事件,而不是调用子作用域的方法,该事件必须由指令作用域changeText侦听,并且在侦听该事件后将触发方法。
NOTE
笔记
Using service / factory would be better approach.
使用服务/工厂会是更好的方法。
This would be hopefully help you. Thanks.
这将是希望帮助你。谢谢。
回答by BernardV
You can achieve calling directive methods without relying on $broadcast or removing scope isolation. Similar approaches that have been posted here so far will break if there are 2+ instances of the directive on a page (they'll all reflect the same changes).
您可以在不依赖 $broadcast 或移除作用域隔离的情况下实现调用指令方法。如果页面上有 2 个以上的指令实例(它们都将反映相同的更改),那么到目前为止已在此处发布的类似方法将中断。
This codependemonstrates a more robust way to do it.
这个 codepen演示了一种更强大的方法来做到这一点。
angular.module('myApp', [])
.controller('myChat', function($scope) {
function room () {return { accessor:{} }; }
$scope.rooms = { 'RoomA': new room, 'RoomB': new room, 'RoomC': new room };
$scope.addMessageTo = function(roomId, msg) {
if ($scope.rooms[roomId].accessor.setMessage)
$scope.rooms[roomId].accessor.setMessage(msg);
};
$scope.addMessages = function () {
$scope.addMessageTo("RoomA", "A message");
$scope.addMessageTo("RoomB", "Two messages");
$scope.addMessageTo("RoomC", "More messages");
}
}).directive('myChatRoom', function() {
return {
template: '<div>{{room}} message = {{message}}<div />',
scope: { accessor: "=", room: "@" },
link: function (scope) {
if (scope.accessor) {
scope.accessor.setMessage = function(msg) {
scope.message = msg;
};
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myChat">
<div ng-repeat="(roomId, room) in rooms">
<div my-chat-room room="{{roomId}}" accessor="room.accessor"></div>
</div>
<button ng-click="addMessages()">Add messages to rooms</button>
</div>
</div>
回答by Pawe? Dziuba?ka
I have another solution, that lets you use isolate scope and don't rely on broadcast. In javascript methods can be used like variables, co you can simply pass the method you want to the directive.
我有另一个解决方案,它可以让您使用隔离范围而不依赖广播。在javascript方法中可以像变量一样使用,你可以简单地将你想要的方法传递给指令。
so in html:
所以在 html 中:
<my-dir text="ctrl.dirText" change-text="ctrl.changeText"></my-dir>
and in directive
并在指令中
scope: {
text: '=',
changeText: '='
}
Hereis slightly modyfied codepen, where You can see what i have in mind.
这是稍微修改过的代码笔,您可以在其中看到我的想法。
回答by Shaunak
You are isolating the scope when you write:
您在编写时正在隔离范围:
scope: {
text: '='
},
Here's a slightly modified version of your code, this time, lets you call directive method. Mostly I just got rid of 'scope'in directive, and changed it to using $scope in the controller, rather than this, and Alias pattern..
这是您的代码的稍微修改版本,这一次,您可以调用指令方法。大多数情况下,我只是摆脱了'scope'in 指令,并将其更改为在控制器中使用 $scope,而不是 this 和 Alias 模式。
WARNING: This might not reflect the correct behavior, with regard's to which variables get changed, but answers your question by showing how you can access directive's method from controller. This is usually not a good design idea..
警告:这可能不能反映正确的行为,关于哪些变量被更改,但通过显示如何从控制器访问指令的方法来回答您的问题。这通常不是一个好的设计理念。
http://codepen.io/anon/pen/azwJBm
http://codepen.io/anon/pen/azwJBm
angular.module('myApp', []).
controller('MyCtrl', function($scope){
var that = this;
$scope.text = 'Controller text';
$scope.dirText = 'Directive text';
$scope.click = function(){
$scope.changeText();
}
}).
directive('myDir', function(){
return {
restrict: 'E',
/* scope: {
text: '='
},*/
link: function(scope, element, attrs){
scope.changeText = function(){
scope.text = 'New directive text';
};
},
template: '<h2>{{text}}</h2>'
};
});
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<h1>{{text}}</h1>
<my-dir text="dirText"></my-dir>
<button ng-click="click()">Change Directive Text</button>
</div>
</div>
回答by Victor
After trying both the $broadcastand the controlobject solutions, I would actually recommend trying to bind values or arrays. The controlobject is a simple way to achieve the desired result, but in my testing very undiscoverable and error-prone.
在尝试$broadcast了control对象和对象解决方案之后,我实际上建议尝试绑定值或数组。该control对象是实现所需结果的简单方法,但在我的测试中非常难以发现且容易出错。
This Codepenbuilds BernardV's example, but uses an array of messages as a very visible control binding. If you want, you can easily $watchthe messages array inside the directive as well. The core idea is to in the directive use:
此 Codepen构建BernardV的示例,但使用消息数组作为非常可见的控件绑定。如果需要,您也可以轻松地$watch在指令中使用消息数组。核心思想是在指令中使用:
scope: { messages: "=", room: "@" },
From a controller (having an array of "rooms") you would do this:
从控制器(具有一组“房间”),您可以执行以下操作:
$scope.addMessages = function () {
angular.forEach($scope.rooms, function(room, index) {
room.messages.push("A new message! # " + (index+1);
})
}
Independent directives, independent messages and highly discoverable. You could of course in the directive only show the latest message, or simply bind a string instead of an array. This solution worked much better for us at least.
独立指令、独立消息和高度可发现性。您当然可以在指令中只显示最新消息,或者简单地绑定一个字符串而不是一个数组。这个解决方案至少对我们来说效果更好。

