1

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

1
  • you did not write an angular directive, your looks like a mix of half directive and half controller !?! check documentation please docs.angularjs.org/guide/directive Commented Aug 25, 2015 at 6:48

2 Answers 2

2

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: {}.

Sign up to request clarification or add additional context in comments.

4 Comments

or rename value in controllerAs property :-)
@Grundy, I only suggested renaming as a test. I don't think it's the right thing to do, since a directive should not be "polluting" the scope where it operates. "Renaming" solves the current issue, but it's just waiting for a hard-to-trace bug to appear.
I will be creating an isolated scope, which suits my purposes.
@NewDev, yep :-) this is just yet another quick fix :-)
0

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!");
         
     }
 }   

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.