Just wondering what's the best way to communication from controller to directive function, i have got an ng-click on one of the button, but the function sit in the directive, is there a way i can call the function within the controller (which sits in directive). i understand u can apply double binding with scope, is there any better way of doing so?
Cheers
app.controller('leadsListing', ['$scope', function($scope){
$scope.filterresultcount = 0;
$scope.records = [];
$scope.filtertotal = '';
$scope.$watch('filtertotal', function(){
$scope.filterresultcount = parseInt($scope.filtertotal / 20);
});
$scope.moreFilterResult = function(){
if($scope.filterresultcount > 0){
$scope.filterresultcount--;
}
$scope.heyJoe(); // It's in diretive
};
}]);
app.directive('recordfilter', ['$http', 'filterService', function($http, filterService){
return {
scope: {
names : '#names',
model : '#model',
records : '=records',
filtertotal : '=filtertotal',
filterresultcount : '=filterresultcount'
},
restrict: 'A',
replace: true,
link: function($scope, iElm, iAttrs, controller) {
$scope.heyJoe()
}
}
}
I believe the best way to implement this kind of controller --> directive communication is to use $scope.$broadcast from the controller, and $scope.$on in the directive's controller/ linking function.
Controller:
app.controller('leadsListing', ['$scope', function($scope){
// ...
$scope.moreFilterResult = function(){
if($scope.filterresultcount > 0){
$scope.filterresultcount--;
}
$scope.$broadcast('joeCalled');
};
}]);
Directive:
app.directive('recordfilter', ['$http', 'filterService', function($http, filterService){
return {
scope: {
names : '#names',
model : '#model',
records : '=records',
filtertotal : '=filtertotal',
filterresultcount : '=filterresultcount'
},
restrict: 'A',
replace: true,
link: function(scope, iElm, iAttrs, controller) {
scope.$on('joeCalled', function(){
// Do something...
});
});
};
}
Edit:
Created a working example of this technique:
http://jsfiddle.net/9p3eyy5h/2/
Calling a function directly in the directive from the controller could be done by placing an empty object on the controller scope, binding it to the directive's scope with '=', and attaching a function to it in the directive's linking function/ controller, which could later be called by the wrapping controller.
Controller:
app.controller('leadsListing', ['$scope', function($scope){
// ...
$scope.directiveFuncs = {};
$scope.moreFilterResult = function(){
if($scope.filterresultcount > 0){
$scope.filterresultcount--;
}
$scope.directiveFuncs.heyJoe();
};
}]);
Directive:
app.directive('recordfilter', ['$http', 'filterService', function($http, filterService){
return {
scope: {
names : '#names',
model : '#model',
records : '=records',
filtertotal : '=filtertotal',
filterresultcount : '=filterresultcount',
// Binding to the controller's func obj
funcs: '='
},
restrict: 'A',
replace: true,
link: function(scope, iElm, iAttrs, controller) {
scope.funcs.heyJoe = function(){
// Do something...
}
});
};
}
HTML:
<div ng-controller="leadsListing">
<div recordfilter funcs="directiveFuncs"></div>
</div>
I would however advise to use my other approach, as it prevents direct dependency between the controller and the directive, and therefor, more robust, so it won't throw an error if the directive is missing or changes.
Working example:
http://jsfiddle.net/9pm3zg5s/1
Related
I'm having an issue with injecting/inheriting a scope from a controller to a directive. Importantly, the module is not separated into its own var.
angular.module('articles').controller('ArticlesController', ['$scope, ...
]).directive('comments', ['$scope' ... //does not work!
You don't inject the scope into a directive as a dependency. Should be like this:
.directive([function() {
return {
"link": function($scope, $element, $attrs) {
//code here
}
}
}]);
The best way is to think about directives as black boxes. You provide it with some data and it updates/displays it. You can read all required info about directives here and declare directive's inputs and outputs like this:
.directive('myDirective', function() {
return {
restrict: 'E',
scope: {
myParameter: '=' //this declares directive's interface (2 way binded)
},
link: function (scope, element) {
console.log(scope.myParameter);
}
};
});
and then you can use this directive as:
<my-directive my-parameter='variable_declared_in_controller'></my-directive>
I just bypassed $scope entirely with a couple of other scopes:
.directive('comments', ['$stateParams', '$location', 'Articles',
function ( $stateParams, $location, Articles) {
if ($stateParams.articleId != null){
var article = Articles.get({
articleId: $stateParams.articleId
});
var comments = {articleId: article.articleId, created: Date.now, comment:"Hello, World!", user: "admin" };
return{
restrict: "A",
scope: true,
template: "<div></div>"
};
}
}
]);
Currently, I am facing one issue related to angularjs directive. I want to send outlet object from directive1 to directive2. Both directives having same controller scope. I tried with emitting event from directive1 to controller, broadcasting that event from controller to directive2 and listening to that event on directive2. but that is not working.
Directive1:
angular.module('moduleName')
.directive('directive1', function() {
return {
restrict: 'E',
templateUrl: 'directive1.html',
scope: false,
link: function(scope) {
scope.selectOutlet = function(outlet) {
scope.order.entityId = outlet.id;
scope.navigation.currentTab = 'right';
};
}
};
Here, in directive1, scope.selectOutlet() setting outletId to scope.order.entityId. I want to move/set that line to directive2 save function.
Directive2:
angular.module('moduleName')
.directive('directive2', function(config, $rootScope, $state) {
return {
restrict: 'E',
templateUrl: 'directive2.html',
scope: false,
link: function(scope) {
scope.save = function() {
// Save functionality
// scope.order.entityId = outlet.id; This is what i want to do
};
}
};
});
});
Any help.
you can use a factory or a service. Inject that factory into your directive. Now when you are trying set the data in function written into factory. `app.factory('shared',function(){
var obj ={};
obj.setData = function(){
// call this function from directive 1.
}
return obj;
})`
So if you include this factory into your directives you will get the data in 2 directives.
I will try to make some jsfiddle or plunker. If it is not clear.
Do the following in first directive
angular.module('moduleName')
.directive('directive1', function($rootScope) {
return {
restrict: 'E',
templateUrl: 'directive1.html',
scope: false,
link: function(scope) {
scope.selectOutlet = function(outlet) {
$rootScope.$broadcast('save:outlet',outlet);
//scope.order.entityId = outlet.id;
//scope.navigation.currentTab = 'right';
};
}
};
and in second
angular.module('moduleName')
.directive('directive2', function(config, $rootScope, $state) {
return {
restrict: 'E',
templateUrl: 'directive2.html',
scope: false,
link: function(scope) {
$rootScope.$on('save:outlet',function(event,data){
// do staff here
});
}
};
});
I have a directive that wraps another one like this :
<div direction from="origin" to="destination">
<div direction-map line-color="#e84c3d"></div>
</div>
the direction-map directive is transcluded, see my code (Fiddle available here) :
var directionController = function() {
//do stuffs
};
var directionMapController = function() {
//do other stuffs
};
var Direction = angular.module("direction", [])
.controller("directionController", directionController)
.controller("directionMapController", directionMapController)
.directive("direction", function() {
var directive = {
restrict: "AEC",
controller: "directionController",
scope: {},
transclude: true,
link: {
pre: function($scope, $element, attrs, controller, transclude) {
console.log("direction's controller is directionController : ");
console.log(controller.constructor === directionController);//true, that's ok
transclude($scope, function(clone) {
$element.append(clone);
});
}
}
};
return directive;
})
.directive("directionMap", function() {
var directive = {
require: "^direction",
controller: "directionMapController",
restrict: "AEC",
scope: true,
link: {
pre: function($scope, $element, $attrs, controller) {
console.log("directionMap's controller is directionMapController :");
console.log(controller.constructor===directionMapController);//false that's not OK!!!!
}
}
};
return directive;
});
So my question is:
Why my child directive direction-map gets as parameter the controller of its parent (I think it's because it is transcluded), is it possible to avoid this or should I just re-think my code ?
It's happening beacause you are using require: "^direction" if you remove this line the directive will get the controller of itself rather than the parent one.
Hope it help :)
Updated Fiddle
I have the following directive:
angular.module('test').directive('childDirective', [function() {
return {
restrict: 'E',
require: '^parentDirective',
controller: function() {
// How do I get parentDirective's controller?
},
link: function($scope, $element, $attrs, $controller) {
var data = $controller.parentDirectiveData;
....
....
}
};
}]);
In the link function I get $controller dependency that holds a reference to parentDirective's controller. How do I get that reference in childDirective's controller?
You have a couple of options, you can either put it on the scope, or store it in a variable that the controller can access also:
angular.module('test').directive('childDirective', [function() {
var parentCtrl;
return {
restrict: 'E',
require: '^parentDirective',
controller: function() {
// parentCtrl will be defined after the link function runs.
},
link: function($scope, $element, $attrs, $controller) {
var data = $controller.parentDirectiveData;
parentCtrl = $controller
}
};
}]);
Importantly please note that the controller function will run before the link function, so you can only really use this in async callbacks.
There is no way to inject the instance of the parent's controller into the child controller before this, because it relies on the directives being bound to the scope in order for that hierarchy to be defined.
Updating as there is some confusion as to what I am asking. I would like to use a directive to inject a variable into the controller used by that directive. I realize I can use the $scope for that, but I don't find that an intuitive solution.
Essentially I want my controller to have the proposal variable injected into it.
My intended usage:
<blah-directive proposal="proposal"></blah-directive>
The directive (so far):
app.directive('blahDirective', function () {
return {
restrict: 'E'
, transclude: true
, replace: true
, scope: {
proposal: '='
}
, templateUrl: 'blahTemp.html'
, controller: blahController
};
});
blahTemp.html
<form class="form-horizontal" role="form" name="myBidForm">
**{{ proposal }}**
</form>
this is displaying the value proposal variable in the $scope fine, but it is not what I want. Essentially I would like to define my controller like:
var blahController = function($scope, SomeOtherResource, proposal) {
}
If you want to inject locals into a controller use $controller.
Here is an example (plunker):
app.directive('blahDirective', function ($controller) {
return {
restrict: 'E',
scope: {
proposal : "="
},
transclude: true,
replace: true,
templateUrl: 'blahTemp.html',
link : function (scope, elm, attrs){
scope.proposal = {};
var locals = {
$scope: scope ,
proposal: scope.proposal
};
$controller('blahController', locals);
}
};
});