0

I'm trying to implement a recursive directive and it seems like to get it to work nicely I need to define an isolate scope as well as have access to the parent scope. Basically I want my directive to have access to variables set as attributes on the directive itself, but i also want to be able to access variables and methods set in the controller's scope. Is there a way to combine the two? I've tried with transclude but i suppose i'm not entirely sure if i've used it properly. Here is a fiddle example of my problem, where i'd like each 'child' in the directive to be able to call the function sayHi(): http://jsfiddle.net/n8dPm/655/

2
  • This would be much easier with a Component (need v1.5+) instead of a Directive. Commented Dec 21, 2017 at 17:25
  • Components let you bind functions, but it breaks when the component is recursive. Events work though: plnkr.co/edit/cZEUsmVjWje3knx4vfHs?p=preview Commented Dec 21, 2017 at 18:08

1 Answer 1

1

You have to pass the sayHi function to your directive. Directives create their own scope, So sayHi function is not part of your directive scope, the way to allow it is by creating a new prop an pass it.

HTML

<div ng-app="myapp">
    <div ng-controller="TreeCtrl">
        <tree family="treeFamily"
          say-hi="sayHi(name)"
         ngTransclude></tree>
    </div>
</div>

JS

var module = angular.module('myapp', []);

module.controller("TreeCtrl", function($scope) {
    $scope.treeFamily = {
        name : "Parent",
        children: [{
            name : "Child1",
            children: [{
                name : "Grandchild1",
                children: []
            },{
                name : "Grandchild2",
                children: []
            }]
        }, {
            name: "Child2",
            children: []
        }]
    };
    $scope.sayHi = function(name){
        alert(name+' says hello!')
    }
});

module.directive("tree", function($compile) {
    return {
        restrict: "E",
        scope: {
            family: '=',
          sayHi : '&'
         },
        transclude: true,
        template: 
            '<p>{{ family.name }}</p>'+
            '<ul>' + 
                '<li ng-repeat="child in family.children">' + 
                    '<tree family="child" say-hi="sayHi(name)"></tree>' +
                    '<button ng-click="sayHi({name : child.name})">Say Hi</button>' +
                '</li>' +
            '</ul>',
        compile: function(tElement, tAttr) {
            var contents = tElement.contents().remove();
            var compiledContents;
            return function(scope, iElement, iAttr) {
                if(!compiledContents) {
                    compiledContents = $compile(contents);
                }
                compiledContents(scope, function(clone, scope) {
                         iElement.append(clone); 
                });
            };
        }
    };
});
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this solution works. It also made me realize directives probably aren't the solution for my problem. In reality my child elements need access to a lot of variables and methods from the parent scope and to pass every one of them down like this weighs down my directive. Ultimately I went with a template based solution described here stackoverflow.com/a/11861030/2963703

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.