21

I want to use something like nesting with custom directives in angular js. Could anyone explain me with simple solution ?

example code is below is not working for me :

<outer>
    <inner></inner>
</outer>

JS

var app = angular.module('app',[]);
app.directive('outer',function(){
    return{
        restrict:'E',
        template:'<div><h1>i am a outer</h1></div>',
        compile : function(elem,attr){
            return function(scope,elem,att,outercontrol){
                outercontrol.addItem(1);
            }
        },
        controller : function($scope){
            this.addItem = function(val){
                console.log(val);
            }
        }
    }
});

app.directive('inner',function(){
    return{
        require : 'outer',
        template : '<div><h1>i am a inner</h1></div>',
        link:function(scope,elem,attr){

        }
    }
});
5
  • 2
    You can do it, but what is the problem? Commented Dec 28, 2014 at 9:53
  • 2
    You have to use transclusion. docs.angularjs.org/api/ng/directive/ngTransclude Commented Dec 28, 2014 at 9:54
  • Yes of-course we can do it in angular, I want to know why isn't working for me. Is there something wrong in the code. I tried transclude to true. It didn't worked. Commented Dec 28, 2014 at 9:58
  • @sajankumar what errors are you getting? Commented Dec 28, 2014 at 10:39
  • @simpe i don't get any errors. It render only outer directive. I want to render it outer and inner directive kind of nesting. Check my code. Commented Dec 28, 2014 at 11:42

2 Answers 2

47

First add restrict:'E' to the inner controller to make it accessible as an element.

Then change the require : 'outer' into require : '^outer', to enable looking for this directive in parents.

Then you need to use transclude to enable the content of the <outer> to be viewed, by the following steps:

  1. add transclude = true to the outer directive.
  2. define where you want the inner data to be viewed. (I guess you need it to appear after the "i am outer" string so you can modify the template of the outer one to be like this template:'<div><h1>i am a outer</h1><div ng-transclude></div></div>').

Then you don't need to the compile parameter at all. As this variable which called outercontrol will not be called at the outer directive but at the inner directive so there is no need to the compile at all for the outer directive and the inner link function will be modified to be like this:

link: function(scope, elem, attr, outercontrol){
    outercontrol.addItem(1);
}

after all this modification the final code will be like the following:

the HTML:

<outer>
<inner></inner>
</outer>

the js:

var app = angular.module("exampleApp",[]);
    app.directive('outer', function(){
        return{
            transclude:true,
            restrict:'E',
            template:'<div><h1>i am a outer</h1><div ng-transclude></div></div>',
            controller : function($scope){
                this.addItem = function(val){
                    console.log(val);
                }
            }
        }
    });

    app.directive('inner',function(){
        return{
            restrict:'E',
            require : '^outer',
            template : '<div><h1>i am a inner</h1></div>',
            link:function(scope,elem,attr,outercontrol){
                outercontrol.addItem(1);
            }
        }
    });
Sign up to request clarification or add additional context in comments.

3 Comments

This is what i exactly want. Thank you so much guys (Y).
@sajankumar You should accept his answer, this was very helpful!
@Mostafa Ahmed I have a problem: In the outer directive I am using Replace: true, but it does not work.. How can I solve? Thnak you
4

If you want a simple solution, check out this plunkr.

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

app.directive('outer', function() {
    return {
        restrict: 'E',
        template: '<div style="border-style:solid"><h1>hey</h1><inner></inner></div>',
    }
});

app.directive('inner', function() {
    return {
        restrict: 'E',
        template: '<div style="border-style:solid"><h1>i am an inner</h1></div>',
    }
});
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.7/angular.js"></script>
<div ng-app="app">
  <outer></outer>
</div>

The problem is that you're nuking the tag with the template attribute of the directive. This line:

    template:'<div><h1>i am a outer</h1></div>',

Does that.

2 Comments

I don't want to nest my directives like your code. I want something like this "<outer><inner></inner></outer>".
This one is not modular and it is sort of against the point of using directives.. you can put all your logic into one directive then.

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.