Calling a parent directive function in a child directive
Hey. I'm trying to create a system pane where elem.bind ('change, ...) in the child directive changes the "selected" parent directive: http://plnkr.co/edit/gc35fuUiJVUhHF4QMAwv?p=preview
(function(angular) {
'use strict';
angular.module('docsTabsExample', [])
.directive('myTabs', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
controller: function($scope) {
var panes = $scope.panes = [];
$scope.select = function(pane) {
angular.forEach(panes, function(pane) {
pane.selected = false;
});
pane.selected = true;
};
$scope.next = function(pane) {
select(panes[panes.indexOf(pane)+1]);
};
this.addPane = function(pane) {
if (panes.length === 0) {
$scope.select(pane);
}
panes.push(pane);
};
},
templateUrl: 'my-tabs.html'
};
})
.directive('myPane', function() {
return {
require: '^myTabs',
restrict: 'E',
transclude: true,
scope: {
title: '@'
},
link: function(scope, element, attrs, tabsCtrl) {
tabsCtrl.addPane(scope);
},
templateUrl: 'my-pane.html'
};
})
.directive('pf-data', function() {
return {
require: '^myPane',
restrict: 'AEC',
scope: {
title: '@'
},
link: function(scope, element, attrs, tabsCtrl) {
console.log("hi");
element.bind('change', function() {
scope.next();
console.log("switch panes");
});
}
};
});
})(window.angular);
(When you select gender (male or female), I want it to go to the next pane sequentially, but I'm guessing due to scope issues (I'm pretty rusty with angular) that it never gets into the associated attribute of the child directive.
Any ideas?
source to share
Each of your directives defines an isolated scope (it's pretty much empty except for the content of the scope
directive's definition element . So when you say scope.next()
it will fail unless it is in that collection or explicitly bound by a function link
, so use $scope
to access your parenting won't work, and you certainly don't want the leaked internal data to be passed through attributes. That should break the gist of these related directives.
But you have something even better.
Since you use require
to chain your directives together, you don't even need to worry about these games. Within, pf-data
you define:
require: ['^myPane', '^myTabs]
This will give you direct access to both controllers. You need to expose next
in the directive myTabs
. To be honest, I would find a way to use indices rather than looping through all of your panels by setting true and false. Something like:
var currentPane;
this.next = function() {
select(nextPane(currentPane));
};
And now, in the pf data, you have access through your function link
:
link: function(scope, element, attrs, ctrls) {
element.bind('change', function() {
$scope.$apply(function() {
ctrls[1].next();
scope.next();
};
});
...
Update
I unlocked the new Plnkr from the one you provided to include the changes we talked about. I also dropped the request myPane
from pf-data
(which would still fail because of transclude
).
http://plnkr.co/edit/LP0RYu6AKxeKyhHY5rZP?p=preview
Updates include:
-
pf-data
was changed topfData
- this is just one of these angular rules. Your directives are named with camel case but end like a hyphen in your html. - I have implemented all the little things that I talked about.
scope.$apply
and changingrequire
to usemyTabs
. As we discussed in the comments, you need to use$apply
whenever you are capturing events that are not directly part of angular in order to signal updates to the elements on the screen. - I am throwing all your methods into
myTabs
onthis
instead of$scope
. You will need them there, since you are going to them through the controller mechanism. - I keep the selected panel in the controller so we can just tell
next()
without supplying the panel.
source to share
You are correct - this is an area problem. When you use isolated scope, the only scope variables that are available in your scoped directives from the parent scope are the ones you pass through attributes. To call next (), which is defined in the parent scope inside your directive, pass the method through the attribute with '&' binding:
scope: {
title:'@',
next: '&'
}
HTML:
<my-pane next="next()"></my-pane>
source to share