Reputation: 4449
Please consider this tryout on Plunkr.
I have a simple set up:
<body ng-app="myApp">
<div ng-controller="myController">
<parent-directive></parent-directive>
<child-directive></child-directive>
</div>
</body>
With the parent directive defined like:
app.directive("parentDirective", [
"$compile",
function (
$compile) {
return {
scope: {
person: "="
},
restrict: "E",
template: "<h3>I'm a parent</h3>",
controller: [
"$scope",
function ($scope) {
// --- PRIVATE --- //
var self = {};
$scope.ClickMe = function() {
alert('Parent clicked');
};
}],
link: function ($scope, $elem, $attrs) {
}
};
}]);
And child directive defined like:
app.directive("childDirective", [
"$compile",
function (
$compile) {
return {
scope: {
person: "="
},
restrict: "E",
require: "^?parentDirective",
template: "<h3>I'm a child, click <button ng-click='ClickMe()'>here</button></h3>",
controller: [
"$scope",
function ($scope) {
// --- PRIVATE --- //
var self = {};
$scope.ClickMe = function() {
alert('child clicked');
$scope.parentDirective.ClickMe();
};
}],
link: function ($scope, $elem, $attrs) {
}
};
}]);
The child
click is handled, but the click defined on the `parent', returns undefined:
TypeError: Cannot read property 'ClickMe' of undefined
looking at the console.
Any idea what's going wrong?
Upvotes: 1
Views: 1284
Reputation: 604
I might be thinking about your problem a little differently but I would take a look at $broadcast. The idea is you can broadcast an event and have "n" number of directives in your case listening for that event.
http://plnkr.co/edit/wBmX2TvC3yMXwItfxkgl
brodcast:
$scope.ClickMe = function() {
alert('child clicked');
$rootScope.$broadcast('child-click');;
};
listen:
$scope.$on('child-click', function (event, args) {
alert('Parent clicked');
});
Upvotes: 0
Reputation:
Any idea what's going wrong?
require
a sibling directive. $scope
. You can require
a directive that is defined on the same element as the requiring directive, or on a parent element.
<child-directive parent-directive></child-directive>
<parent-directive>
<child-directive></child-directive>
</parent-directive>
When you require
the controller (aka. exposed API) of another directive, it doesn't magically end up on the $scope of the requiring directive.
It does however end up in your link
function as the fourth argument.
Like so:
.directive('child', function () {
return {
require: '?^parentDirective',
link: function (scope, el, attrs, parentDirectiveController) {
scope.clickMe = function () {
parentDirectiveController.clickMe();
};
}
};
});
Expose the methods you want available in other directives onto this
instead of $scope, as the $scope way of doing it won't work the way you intend it to when you have isolated scopes.
.directive('parent',
controller: function () {
this.clickMe = function () {};
}
}
To get your example working;
<parent>
<child></child>
</parent>
.directive('parent', function () {
return {
controller: function () {
this.clickMe = function () {};
}
};
}
.directive('child', function () {
return {
require: '^?parent',
link: function (scope, el, attrs, parentCtrl) {
scope.clickMe = function () {
parentCtrl.clickMe();
};
}
};
});
Simplified (& working) version of your plunker: http://plnkr.co/edit/nao4EvbptQm7gDKkmZS2?p=preview
Upvotes: 1
Reputation: 36
Put your child directive in your parent directive template. Then use $scope.$parent.ClickMe(). Here's what it would look like.
Simple setup:
<body ng-app="myApp">
<div ng-controller="myController">
<parent-directive></parent-directive>
</div>
</body>
Parent directive:
app.directive("parentDirective", [
function () {
return {
scope: {},
restrict: "E",
template: "<h3>I'm a parent</h3><child-directive></child-directive>",
controller: [
"$scope",
function ($scope) {
$scope.ClickMe = function() {
alert('Parent clicked');
};
}
]
};
}
]);
Child directive:
app.directive("childDirective", [
function () {
return {
restrict: "E",
template: "<h3>I'm a child, click <button ng-click='ClickMe()'>here</button></h3>",
controller: [
"$scope",
function ($scope) {
$scope.ClickMe = function() {
alert('child clicked');
$scope.$parent.ClickMe();
};
}
]
};
}
]);
Upvotes: 0