Reputation: 2158
I have 3 directives, "parenta", "parentb", and "childb". "parenta" and "parentb" are siblings, while "childb" is a direct child of "parentb".
I am trying to call a controller method from "parenta", however it is not working. For some strange reason, trying to call a method on "childb" controller FROM "parenta" is working instead. What is happening?
var mod = angular.module("app", []);
mod.directive("parenta", function () {
return {
template: "<section><div ng-click='vm.a()'>Rendered by a</div></section>",
replace: false,
controllerAs: "vm",
controller: function () {
this.a = function () {
console.log("a called!");
}
}
}
})
mod.directive("parentb", function () {
return {
template: "<childb></childb>",
replace: false
}
})
mod.directive("childb", function () {
return {
template: "<section><div ng-click='vm.b()'>Rendered by b</div></section>",
replace: false,
controllerAs: "vm",
controller: function () {
this.b = function () {
console.log("b called!");
}
}
}
})
Html:
<div ng-app="app">
<parenta></parenta>
<parentb></parentb>
</div>
Codepen: http://codepen.io/anon/pen/pJMpVe
Upvotes: 1
Views: 1086
Reputation: 41
I used link function instead of controller.
Directive controllers are used in AngularJS for inter-directive communication, while link functions are fully contained and specific to the directive instance. By interdirective communication, we mean when one directive on an element wants to communicate with another directive on its parent or on the same element. This encompasses sharing state or variables, or even functions.
In the below code I commented the controller function and placed link function
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
</head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script type="text/javascript">
var mod = angular.module("app", []);
mod.directive("parenta", function () {
return {
/*template: "<section><div ng-click='vm.a()'>Rendered by a</div></section>",*/
template: "<section><div ng-click='a()'>Rendered by a</div></section>",
replace: false,
link: function($scope,$element,$attrs)
{
$scope.a = function()
{
console.log("a called!");
}
}
/* controllerAs: "vm",
controller: function () {
this.a = function () {
alert("a called!");
console.log("a called!");
}
}
*/
}
})
mod.directive("parentb", function () {
return {
template: "<childb></childb>",
replace: false
}
})
mod.directive("childb", function () {
return {
template: "<section><div ng-click='vm.b()'>Rendered by b</div></section>",
replace: false,
controllerAs: "vm",
controller: function () {
this.b = function () {
console.log("b called!");
}
}
}
})
</script>
<body>
<div ng-app="app">
<parenta></parenta>
<parentb></parentb>
</div>
</body>
</html>
or if we want to use controller directive then better to use Directive Isolate Scopes along with.
Unlike a controller, which is paired with a newly created scope when created, a directive is not given a scope of its own by default. Instead, it simply uses the scope that is available, based on its location in the DOM.
Isolate scope just means giving the directive a scope of its own that does not inherit from the existing scope.
so we use
scope: true in our parenta
mod.directive("parenta", function () {
return {
template: "<section><div ng-click='vm.a()'>Rendered by a</div></section>",
replace: false,
scope: true , // Isolate scope
controllerAs: "vm",
controller: function () {
this.a = function () {
console.log("a called!");
}
}
Upvotes: 0
Reputation: 49590
The issue here is that your directives do not create a child or an isolate scope and use scope: false
(which is the default).
That means that for a given scope, each directive with its aliased controller, create a scope property called vm
- both on the same scope. And so, childb
overwrites the vm
property initially created by parenta
.
You can check this quite easily - change one of controllerAs aliases to something else.
An easy fix - and the right thing to do - is to use either scope: true
or scope: {}
.
Upvotes: 2