AngularJS ─ can't get scope by link from the directive controller

400 Views Asked by At

I have an example app with very simple structure (you may see it here: http://plnkr.co/edit/5VAqUQsqKFGoteahacR2?p=preview): The file index.html includes template (app/templates/home.html), which, in turn, includes the directive's template:

<div class="included" ng-include="'app/templates/outer-directive-2.html'"></div>

It includes the next directive:

<p>This is the included file <b>app/templates/outer-directive-2.html</b></p>
<div inner2="context"></div>

The value of the param inner2 is the key for the $scope.contents object which is defined in the contentsCtrl controller:

app.controller('contentsCtrl', function($scope,$rootScope){

    $scope.contents = {
        context: "Context for investigations here."
    }

});

This key is needed to extract the object field in the directive's script (app/scripts/directives/defaultDirective.js):

app.directive('inner2', function(){
    return{
        restrict: 'A',
        replace: true,
        scope: {
            inner2: '@',
            contents: '&'
        },
        templateUrl: 'app/templates/inner-directive-2.html',
        controller: function($scope){
            $scope.getStuff = function(){
                console.log('$scope.inner2, $scope.contents', {
                    // returns the key "context"
                    '$scope.inner2':$scope.inner2,
                    // returns function (???)
                    '$scope.contents':$scope.contents,
                    // returns "undefined"
                    '$scope.context':$scope.contents[$scope.inner2]
                });
            }
        }
    };
});

The content of that last folded directive (app/templates/inner-directive-2.html) is very simple:

<div class="included" title="{{inner2}}">
    <p>Hello, I am the inner directive 2</p>
    <span class="pseudolink" ng-click="getStuff()">Click me</span> and check console message!
</div>

So the idea is to get the $scope.contents[object_key] by calling getStuff(). But it can't see $scope.contents. I thought that it may be done by binding the isolated scope param (see above) contents to the outer scope:

scope: {
    ....
    contents: '&'
},

...but it doesn't return the scope object, it returns function instead. Probably something is wrong here. The questions are: 1. Why function and where it comes from? 2. May I get $scope.contents by some way and how?

http://plnkr.co/edit/5VAqUQsqKFGoteahacR2?p=preview

2

There are 2 best solutions below

0
On

According to the angular`s docs:

& or &attr - provides a way to execute an expression in the context of the parent scope. If no attr name is specified then the attribute name is assumed to be the same as the local name. Given and the isolate scope definition scope: { localFn:'&myAttr' }, the isolate scope property localFn will point to a function wrapper for the count = count + value expression. Often it's desirable to pass data from the isolated scope via an expression to the parent scope. This can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is increment(amount) then we can specify the amount value by calling the localFn as localFn({amount: 22})

so scope.contents in your directive will be a wrapper function. You should either pass your contents object into directive scope or modify doStuff to execute it in the context of the parent scope.

Like in the doc (plese look at the example with increment(amount)) your doStuff should be in the parent scope. And from the directive you could pass locale variables

0
On

You are already getting scope contents. It's just that you didn't defined the default route to home rather it was set 404. Please check the updated plunker - http://plnkr.co/edit/BlXBqK?p=preview

Let me know if you are looking for something else.

app.config(function($stateProvider, $urlRouterProvider){

    $urlRouterProvider.otherwise("/home");

    $stateProvider
        .state('home',{
            url: "/home",
            templateUrl: 'app/templates/home.html'
        })
        .state('error',{
            url: "/404",
            templateUrl: "app/templates/404.html"
        });
});