从其他控制器调用指令控制器中的方法
我有一个指令,有自己的控制器。 看下面的代码:
var popdown = angular.module('xModules',[]); popdown.directive('popdown', function () { var PopdownController = function ($scope) { this.scope = $scope; } PopdownController.prototype = { show:function (message, type) { this.scope.message = message; this.scope.type = type; }, hide:function () { this.scope.message = ''; this.scope.type = ''; } } var linkFn = function (scope, lElement, attrs, controller) { }; return { controller: PopdownController, link: linkFn, replace: true, templateUrl: './partials/modules/popdown.html' } });
这意味着成为错误/通知/警告的通知系统。 我想要做的是从另一个控制器(而不是一个指令)来调用该控制器上的functionshow
。 而当我这样做,我也希望我的链接函数检测到一些属性更改和执行一些animation。
下面是一些代码来说明我所要求的:
var app = angular.module('app', ['RestService']); app.controller('IndexController', function($scope, RestService) { var result = RestService.query(); if(result.error) { popdown.notify(error.message, 'error'); } });
所以在popdown
指令控制器上调用show
时,链接函数也应该被触发并执行一个animation。 我怎么能做到这一点?
这是一个有趣的问题,我开始考虑如何实现这样的事情。
我想出了这个(小提琴) ;
基本上,我没有试图从控制器调用指令,而是创build了一个模块来容纳所有的popup式逻辑:
var PopdownModule = angular.module('Popdown', []);
我把两件事情放在模块中,一个可以在任何地方注入的API的factory
,以及定义实际popup元素行为的directive
:
工厂只是定义了一些函数的success
和error
并跟踪了一些variables:
PopdownModule.factory('PopdownAPI', function() { return { status: null, message: null, success: function(msg) { this.status = 'success'; this.message = msg; }, error: function(msg) { this.status = 'error'; this.message = msg; }, clear: function() { this.status = null; this.message = null; } } });
该指令获取API注入其控制器,并观察api的变化(我使用引导CSS的方便):
PopdownModule.directive('popdown', function() { return { restrict: 'E', scope: {}, replace: true, controller: function($scope, PopdownAPI) { $scope.show = false; $scope.api = PopdownAPI; $scope.$watch('api.status', toggledisplay) $scope.$watch('api.message', toggledisplay) $scope.hide = function() { $scope.show = false; $scope.api.clear(); }; function toggledisplay() { $scope.show = !!($scope.api.status && $scope.api.message); } }, template: '<div class="alert alert-{{api.status}}" ng-show="show">' + ' <button type="button" class="close" ng-click="hide()">×</button>' + ' {{api.message}}' + '</div>' } })
然后我定义一个依赖于Popdown
的app
模块:
var app = angular.module('app', ['Popdown']); app.controller('main', function($scope, PopdownAPI) { $scope.success = function(msg) { PopdownAPI.success(msg); } $scope.error = function(msg) { PopdownAPI.error(msg); } });
而HTML看起来像:
<html ng-app="app"> <body ng-controller="main"> <popdown></popdown> <a class="btn" ng-click="success('I am a success!')">Succeed</a> <a class="btn" ng-click="error('Alas, I am a failure!')">Fail</a> </body> </html>
我不确定它是否完全理想,但似乎是一个合理的方式来build立沟通与全球ishpopup式指令。
再次,作为参考, 小提琴 。
您也可以使用事件来触发popup窗口。
这是基于satchmorun解决scheme的小提琴 。 它省去了PopdownAPI,而顶层控制器改为在作用域链上$broadcast
“成功”和“错误”事件:
$scope.success = function(msg) { $scope.$broadcast('success', msg); }; $scope.error = function(msg) { $scope.$broadcast('error', msg); };
Popdown模块然后为这些事件注册处理函数,例如:
$scope.$on('success', function(event, msg) { $scope.status = 'success'; $scope.message = msg; $scope.toggleDisplay(); });
这至less起作用,在我看来这是一个很好的解耦scheme。 如果出于某种原因被认为是不好的做法,我会让别人join。
你也可以将指令的控制器暴露给父范围,就像name
ngForm
属性一样: http : ngForm
: ngForm
在这里你可以find一个非常基本的例子,它可以实现http://plnkr.co/edit/Ps8OXrfpnePFvvdFgYJf?p=preview
在这个例子中,我有myDirective
与$clear
方法专用控制器(sorting非常简单的公共API的指令)。 我可以将此控制器发布到父范围,并使用在该指令外调用此方法。
我有更好的解决scheme。
这里是我的指令,我已经在指令中注入了对象引用,并通过在指令代码中添加invoke函数来扩展该指令。
app.directive('myDirective', function () { return { restrict: 'E', scope: { /*The object that passed from the cntroller*/ objectToInject: '=', }, templateUrl: 'templates/myTemplate.html', link: function ($scope, element, attrs) { /*This method will be called whet the 'objectToInject' value is changes*/ $scope.$watch('objectToInject', function (value) { /*Checking if the given value is not undefined*/ if(value){ $scope.Obj = value; /*Injecting the Method*/ $scope.Obj.invoke = function(){ //Do something } } }); } }; });
使用参数在HTML中声明指令:
<my-directive object-to-inject="injectedObject"></ my-directive>
我的控制器:
app.controller("myController", ['$scope', function ($scope) { // object must be empty initialize,so it can be appended $scope.injectedObject = {}; // now i can directly calling invoke function from here $scope.injectedObject.invoke(); }];