I have a directive that has its own controller. See the below code:
我有一个有自己控制器的指令。看下面的代码:
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'
}
});
This is meant to be a notification system for errors/notifications/warnings. What I want to do is from another controller (not a directive one) to call the function show
on this controller. And when I do that, I would also want my link function to detect that some properties changed and perform some animations.
这是一个错误/通知/警告的通知系统。我要做的是从另一个控制器(不是指令控制器)调用这个控制器上显示的函数。当我这样做的时候,我也希望我的link函数检测到一些属性发生了变化并执行一些动画。
Here is some code to exemplify what I'm asking for:
这里有一些代码来举例说明我所要求的:
var app = angular.module('app', ['RestService']);
app.controller('IndexController', function($scope, RestService) {
var result = RestService.query();
if(result.error) {
popdown.notify(error.message, 'error');
}
});
So when calling show
on the popdown
directive controller, the link function should also be triggered and perform an animation. How could I achieve that?
因此,当在popdown指令控制器上调用show时,链接函数也应该被触发并执行动画。我怎么能做到呢?
4 个解决方案
#1
166
This is an interesting question, and I started thinking about how I would implement something like this.
这是一个有趣的问题,我开始思考如何实现这样的东西。
I came up with this (fiddle);
我想出了这个(小提琴);
Basically, instead of trying to call a directive from a controller, I created a module to house all the popdown logic:
基本上,我没有尝试从控制器调用指令,而是创建了一个模块来存放所有弹出式逻辑:
var PopdownModule = angular.module('Popdown', []);
I put two things in the module, a factory
for the API which can be injected anywhere, and the directive
for defining the behavior of the actual popdown element:
我在模块中放入了两个东西,一个可以被注入任何地方的API工厂,以及定义实际弹出元素行为的指令:
The factory just defines a couple of functions success
and error
and keeps track of a couple of 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;
}
}
});
The directive gets the API injected into its controller, and watches the api for changes (I'm using bootstrap css for convenience):
该指令将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>'
}
})
Then I define an app
module that depends on Popdown
:
然后我定义一个app模块,它依赖于Popdown:
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); }
});
And the HTML looks like:
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>
I'm not sure if it's completely ideal, but it seemed like a reasonable way to set up communication with a global-ish popdown directive.
我不确定它是否完全理想,但它似乎是一种合理的方式来建立与一个全球化的popdown指令的通信。
Again, for reference, the fiddle.
作为参考,小提琴。
#2
26
You can also use events to trigger the Popdown.
您还可以使用事件来触发弹出窗口。
Here's a fiddle based on satchmorun's solution. It dispenses with the PopdownAPI, and the top-level controller instead $broadcast
s 'success' and 'error' events down the scope chain:
这是一个基于satchmorun解决方案的小提琴。它不使用PopdownAPI,而*控制器则在作用域链中以$broadcast 'success'和'error'事件:
$scope.success = function(msg) { $scope.$broadcast('success', msg); };
$scope.error = function(msg) { $scope.$broadcast('error', msg); };
The Popdown module then registers handler functions for these events, e.g:
弹出式模块然后为这些事件注册处理程序函数,例如:
$scope.$on('success', function(event, msg) {
$scope.status = 'success';
$scope.message = msg;
$scope.toggleDisplay();
});
This works, at least, and seems to me to be a nicely decoupled solution. I'll let others chime in if this is considered poor practice for some reason.
至少,这是可行的,在我看来,这是一个很好的解耦解决方案。如果出于某种原因,这种做法被认为是不恰当的,我会让其他人加入进来。
#3
11
You could also expose the directive's controller to the parent scope, like ngForm
with name
attribute does: http://docs.angularjs.org/api/ng.directive:ngForm
您还可以将该指令的控制器公开给父范围,如具有name属性的ngForm: http://docs.angularjs.org/api/ng.directive:ngForm
Here you could find a very basic example how it could be achieved http://plnkr.co/edit/Ps8OXrfpnePFvvdFgYJf?p=preview
在这里,您可以找到一个非常基本的示例,说明如何实现http://plnkr.co/edit/ps8oxrfpnepvvdfgyjf?
In this example I have myDirective
with dedicated controller with $clear
method (sort of very simple public API for the directive). I can publish this controller to the parent scope and use call this method outside the directive.
在这个例子中,我有myDirective with专用控制器和$clear方法(类似于指令的非常简单的公共API)。我可以将这个控制器发布到父作用域,并在指令之外调用这个方法。
#4
3
I got much better solution .
我有更好的解决办法。
here is my directive , I have injected on object reference in directive and has extend that by adding invoke function in directive code .
这是我的指令,我在指令中注入了对象引用,并通过在指令代码中添加调用函数来扩展它。
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
}
}
});
}
};
});
Declaring the directive in the HTML with a parameter:
使用参数在HTML中声明指令:
<my-directive object-to-inject="injectedObject"></ my-directive>
my Controller:
我的控制器:
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();
}];
#1
166
This is an interesting question, and I started thinking about how I would implement something like this.
这是一个有趣的问题,我开始思考如何实现这样的东西。
I came up with this (fiddle);
我想出了这个(小提琴);
Basically, instead of trying to call a directive from a controller, I created a module to house all the popdown logic:
基本上,我没有尝试从控制器调用指令,而是创建了一个模块来存放所有弹出式逻辑:
var PopdownModule = angular.module('Popdown', []);
I put two things in the module, a factory
for the API which can be injected anywhere, and the directive
for defining the behavior of the actual popdown element:
我在模块中放入了两个东西,一个可以被注入任何地方的API工厂,以及定义实际弹出元素行为的指令:
The factory just defines a couple of functions success
and error
and keeps track of a couple of 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;
}
}
});
The directive gets the API injected into its controller, and watches the api for changes (I'm using bootstrap css for convenience):
该指令将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>'
}
})
Then I define an app
module that depends on Popdown
:
然后我定义一个app模块,它依赖于Popdown:
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); }
});
And the HTML looks like:
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>
I'm not sure if it's completely ideal, but it seemed like a reasonable way to set up communication with a global-ish popdown directive.
我不确定它是否完全理想,但它似乎是一种合理的方式来建立与一个全球化的popdown指令的通信。
Again, for reference, the fiddle.
作为参考,小提琴。
#2
26
You can also use events to trigger the Popdown.
您还可以使用事件来触发弹出窗口。
Here's a fiddle based on satchmorun's solution. It dispenses with the PopdownAPI, and the top-level controller instead $broadcast
s 'success' and 'error' events down the scope chain:
这是一个基于satchmorun解决方案的小提琴。它不使用PopdownAPI,而*控制器则在作用域链中以$broadcast 'success'和'error'事件:
$scope.success = function(msg) { $scope.$broadcast('success', msg); };
$scope.error = function(msg) { $scope.$broadcast('error', msg); };
The Popdown module then registers handler functions for these events, e.g:
弹出式模块然后为这些事件注册处理程序函数,例如:
$scope.$on('success', function(event, msg) {
$scope.status = 'success';
$scope.message = msg;
$scope.toggleDisplay();
});
This works, at least, and seems to me to be a nicely decoupled solution. I'll let others chime in if this is considered poor practice for some reason.
至少,这是可行的,在我看来,这是一个很好的解耦解决方案。如果出于某种原因,这种做法被认为是不恰当的,我会让其他人加入进来。
#3
11
You could also expose the directive's controller to the parent scope, like ngForm
with name
attribute does: http://docs.angularjs.org/api/ng.directive:ngForm
您还可以将该指令的控制器公开给父范围,如具有name属性的ngForm: http://docs.angularjs.org/api/ng.directive:ngForm
Here you could find a very basic example how it could be achieved http://plnkr.co/edit/Ps8OXrfpnePFvvdFgYJf?p=preview
在这里,您可以找到一个非常基本的示例,说明如何实现http://plnkr.co/edit/ps8oxrfpnepvvdfgyjf?
In this example I have myDirective
with dedicated controller with $clear
method (sort of very simple public API for the directive). I can publish this controller to the parent scope and use call this method outside the directive.
在这个例子中,我有myDirective with专用控制器和$clear方法(类似于指令的非常简单的公共API)。我可以将这个控制器发布到父作用域,并在指令之外调用这个方法。
#4
3
I got much better solution .
我有更好的解决办法。
here is my directive , I have injected on object reference in directive and has extend that by adding invoke function in directive code .
这是我的指令,我在指令中注入了对象引用,并通过在指令代码中添加调用函数来扩展它。
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
}
}
});
}
};
});
Declaring the directive in the HTML with a parameter:
使用参数在HTML中声明指令:
<my-directive object-to-inject="injectedObject"></ my-directive>
my Controller:
我的控制器:
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();
}];