1

I want to use my directives within other directives. The following example gives so strange results that I had to give up and ask this question. I would like someone to explain me what is going on here:

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

app.directive('one', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<outer>one</outer>'
    };
});

app.directive('two', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<outer>two</outer>'
    };
});

app.directive('outer', function() {
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        template: '<div ng-transclude></div>'
    };
});

HTML:

    <outer>whatever</outer>
    <one></one>
    <two></two>
    <outer>something</outer>

The resulting DOM is:

    <div ng-transclude=""></div>
    <outer></outer>
    <two></two>
    <outer>something</outer> 

JSFiddle: http://jsfiddle.net/WPpUL/

Is it a bug?

EDIT:

Expected output DOM:

    <div ng-transclude>whatever</div>
    <div ng-transclude>one</div>
    <div ng-transclude>two</div>
    <div ng-transclude>something</div>
5
  • 1
    You do get an error Commented Nov 15, 2013 at 15:18
  • You're right, I missed it. Still, none of the cases mentioned there seem to match this example. And how to explain different results of one and two, as well as first and second usage of outer? Why they don't behave the same every time? Commented Nov 15, 2013 at 16:24
  • could you give an example of what you'd want the output to be? Commented Nov 15, 2013 at 16:38
  • 1
    Changing One and Two to use replace: false also resolves this. For some reason under the combination you have angular thinks two directives are competing to apply templates and thus your error. It appears you're not the only one puzzled by this. The last question here is very similar to yours: docs.angularjs.org/error/… Commented Nov 15, 2013 at 16:42
  • @KayakDave Thanks, though this significantly alters the DOM, just as wrapping template with DIV or other tag. In my opinion it is a bug. Anyway, good to know I'm not alone ;) Commented Nov 15, 2013 at 16:51

2 Answers 2

1

Instead of using replace we'll do it manually- this seems to keep angular happy and gets you what you need.

1) Set replace: false instead of true in One and Two. (making angular happy)

2) Manually replace the html using this link function to One and Two:

link: function(scope, element, attrs) {
    element.replaceWith(element.html());
}

This will result in:

<div ng-transclude=""><b class="ng-scope">whatever</b></div>
<div ng-transclude=""><b class="ng-scope">one</b></div>
<div ng-transclude=""><b class="ng-scope">two</b></div>
<div ng-transclude=""><b class="ng-scope">something</b></div> 

The text nodes have been surrounded by B tags to get rid of automatically generated SPANs.

Here's the updated fiddle: http://jsfiddle.net/WPpUL/7/

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks, I forgot about element. Well, I see it's quite a hard problem. Is there no perfect solution? :(
Looks like there is- I just updated the answer. The final piece was doing the replace manually- which keeps Angular from complaining while getting you what you need.
And now that we do the replaceWith() you can use transclude: true or element. True gets you a span while element uses outer.
hmm, it doesn't work with dynamic content, for example: <one><p ng-repeat="item in list">{{item}}</p></one>
Not all directives need a new scope. But some, like ng-repeat do. The problem is that Angular uses that 'ng-binding', that we stripped, for the $watch it uses to see if any dynamic data has changed. It was cool to strip those when your element was static. But without the element decorated with ng-binding the element loses it's two way binding. You can see how ng-binding is used in the ngBind source code: github.com/angular/angular.js/blob/…
|
1

Wrap template with a root element will fix the problem

template: '<div><outer>one</outer></div>'
template: '<div><outer>two</outer></div>'

1 Comment

And what if I don't want to change the DOM? Why the outer directive can't be a child of another directive with transclusion?

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.