5
votes

I am writing my angularjs directive with definition like:

return {
    restrict: 'EA',
    link: link,
    scope: true,
    transclude: true,
    replace: true,
    controller: controller,
    template: '<div class="wizard">' +
        '<div ng-transclude></div>' +
        '</div>'
};

I notice two scopes was created:

< Scope (003)  --- parent scope of directive
    < Scope (004)  --- controller scope of directive which I think is child scope created by 'scope=true'. all my functions, properites defined in controller show up in this scope
    < Scope (005)  --- transclude scope which is empty

from the document I am expecting only one child scope was created because 'scope=true' will not create an isolated scope. this leads all elements replaced by 'ng-transclude' actually inherit Scope(005) and have no access to my functions/properties defined in controller because they are in Scope(004) which is a sibling of Scope(005).

I don't know what's going wrong, can somebody throw some lights here?

And when using Chrome debugger to watch my elements, I notice these elements were added by a class "ng-scope", however, how can I match "ng-scope" to scopes showing in batarang console? like show ng-scope's id.

thanks

2

2 Answers

15
votes

scope: true will create a new child scope that prototypically inherits from the controller scope – this is Scope 004.

scope: { ... } would create a new child scope that does not prototypically inherit from the controller scope.

Either way, a new child scope is created.

In addition, because you are using transclude: true, another (transcluded) child scope 005 is created. Transcluded scopes always prototypically inherit from the controller scope.

As you already discovered, properties and functions that you define on the directive scope (i.e., inside your directive) are not available to the view because the view uses the transcluded scope.

enter image description here

The picture above is based on the following code:

app.directive('myDirective', function() {
    return {
        restrict: 'EA',
        //link: link,
        scope: true,
        transclude: true,
        replace: true,
        controller: function($scope) {
            $scope.dirProp1 = "dirProp1";
            $scope.dirFunc = function() {}
        },
        template: '<div class="wizard">' +
            '<div ng-transclude></div>' +
            '</div>'
    };
});

function MyCtrl($scope) {
    $scope.parentCtrlProp1 = 'ParentCtrlProp1';
}

So, as you can see from the diagram, the transcluded scope (hence the transcluded content) can only access properties and functions defined on the controller scope (003), via the prototype chain.


how can I match "ng-scope" to scopes showing in batarang console? like show ng-scope's id.

I'm not aware of any way to do this (which is why I wrote a tool to draw my own pictures).

2
votes

it's hard to figure out without any jsfiddle for the context. What is your link function? and what is your controller function?

By the way, it is the normal behaviour as documentation says transclude:true creates also a new scope.

Look at here : https://github.com/angular/angular.js/wiki/Understanding-Scopes

The transcluded and the isolated scope (if any) are siblings -- the $parent property of each scope references the same parent scope. When a transcluded and an isolate scope both exist, isolate scope property $$nextSibling will reference the transcluded scope.

So if you want to access the 2 siblings from one another, you have to use a 2-way binding with their parent