emertechie
emertechie

Reputation: 3857

Accessing parent controller in dynamically generated AngularJS directive

I have some items stored in a database. Each item has a 'type'. I want to use this type to dynamically insert a directive based on the type. My html would look like:

<ul>
  <li my-item ng-repeat="item in items"></li>
</ul

In the my-item directive I dynamically generate a directive as follows:

app.directive('myItem', function($compile){
    return {
        link: function(scope, el, attrs) {
            var concreteTypeEl = $compile('<div my-item-' + scope.item.type + ' item="item"></div>')(scope);
            el.append(concreteTypeEl);
        }
    };
});

And then I have further directives defining the 'concrete' item type. For example an item with type 'Type1' would use the 'myItemType1' directive (shown below)

So that's all fine. Now, I also want a parent directive to wrap all instances of these directives and provide a controller to allow coordination between them.

I use the require ^parentCtrl syntax on the myItem directive to access the parent controller.

My problem is that this doesn't work for any of the 'dynamically' inserted directives such as 'myItemType1'

Full example below and in this plunkr. The markup:

<body ng-controller="MainCtrl">
    <div my-container>
        <ul>
            <li my-item ng-repeat="item in items"></li>
        </ul>
    </div>
</body>

The code:

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

app.controller('MainCtrl', function($scope) {
    $scope.items = [{
        type: 'type1',
        content: 'Type 1 item'
    }, {
        type: 'type1',
        content: 'Another Type 1 item'
    }];
});

app.directive('myContainer', function(){
    return {
        controller: function() {
            this.doSomething = function() {
                return 'foo';
            }
        }
    };
});

app.directive('myItem', function($compile){
    return {
        require: '^myContainer',
        link: function(scope, el, attrs, myContainer) {

            // 'myContainer' is a reference to parent controller
            console.log('Ctrl in myItem:', myContainer);

            var concreteTypeEl = $compile('<div my-item-' + scope.item.type + ' item="item"></div>')(scope);
            el.append(concreteTypeEl);
        }
    };
});

app.directive('myItemType1', function($compile){
    return {
        require: '?^myContainer',
        link: function(scope, el, attrs, myContainer) {

            // PROBLEM: 'myContainer' is undefined here
            console.log('Ctrl in myItemType1:', myContainer);

            el.append(scope.item.content);
        }
    };
});

Am I approaching this all wrong?

Upvotes: 2

Views: 655

Answers (1)

Michael Kang
Michael Kang

Reputation: 52867

You should append the element to the DOM tree before you manually compile and link it:

link:function(scope,element,attr) {
    // create the element
    var e = angular.element('<my-child></my-child>');           
    //append it to the DOM  
    element.append(e);
    // compile and link
    $compile(e)(scope);
}

Demo Fiddle

Upvotes: 3

Related Questions