Repository: angular/angular.js

Issue #5489: ng-transclude should not create new sibling scope.
Created: 2013-12-20T00:41:51Z
This is more of a change request and I would like to see what other people think.
In my humble opinion ng-transclude should not create it's own scope or at least have a way to prevent it from doing so. The reason behind this is that a directive which requests transclusion already has means to specify whether or not it wants to have a scope or an isolated scope or no scope at all. It uses ng-transclude directive to mark where it wants to insert the content. When ng-transclude creates it's own sibling scope it kind of breaks the expectations of the directive which defines what kind of scope it wants and there comes the manifestation of the popular 'value' vs 'object.value' confusion.
Here's an example of where new scope doesn't make sense in my opinion:
ui.directive('box', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: '<div ng-transclude/>',
        replace: true,
        scope: {}
    };
});

All this directive wants is replace the <box>content</box> with a <div>content</div> and the content to have the isolated scope.
Creating nested structure of directives like this leads to a scope tree pollution. Here's a plunker example (http://plnkr.co/edit/DwukVGGprFFjQuVY8yTz) of three nested directives which create a scope tree structure like this:
< Scope (002) : ng-app
    < Scope (003) : ng-controller
        < Scope (004) : box
        < Scope (005) : ng-transclude
            < Scope (006) : box
            < Scope (007) : ng-transclude
                < Scope (008) : box
                < Scope (009) : ng-transclude

This behaviour doesn't seem to add any value to its purpose but creates a lot of confusion among beginners.
At the moment I use the following workaround which achieves exactly what the previous example does:
ui.directive('box', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: '<div/>',
        replace: true,
        scope: {},
        link: function(scope, element, attrs, transclude) {
            transclude(scope.$parent, function(content) {
                element.append(content);
            });
        }
    };
});

Here's a plunker example (http://plnkr.co/edit/46v6IBLkhS71L1WbUDFl) which illustrates this concept. It leaves the scope tree nice and tidy:
< Scope (002) : ng-app
    < Scope (003) : ng-controller
        < Scope (004) : box
        < Scope (005) : box
        < Scope (006) : box

And the 2-way binding works the way many expect when they bind 'value' rather than 'object.value'. (I believe that the fact that passing just 'value' works in some cases but not the other and blaming the nature of prototypal inheritance in javascript is not a good excuse. The fact that many people find this behaviour unexpected indicates that there's an architectural flaw.)
I would love to hear what other people think and use cases where they think that creating a new sibling scope for ng-transclude makes sense.

Duplicate issue #8609: ngTransclude creates illogical scope
Created: 2014-08-14T05:09:43Z
Hi all,
When one is using ng-transclude it is often used to dress-up some existing elements. A prime example is an input tag that one would put a label on. and perhaps add some logic to display stuff depending on its value. It is confusing (especially to beginners) that a new scope gets created by ng-transclude.
I created a small plunk to illustrate my issue here.
the prime offender is in this directive
     function pane() {
        return {
           restrict: 'E',
           transclude: true,
           scope: {
              title: '@'
           },
           template: '<div style="border: 1px solid black;">' +
              '<div style="background-color: gray">{{title}} (isolate scope id: {{$id}})</div>' +
              '<ng-transclude></ng-transclude>' +
              '</div>'
        };
     }

When a user does something like this:
<form>
    <pane title='enter your name'>
         <input type='text ngModel='username'>
    </pane>
    <pane title='enter your token'>
         <input type='text ngModel='token'>
   </pane>

   
The result will be surprising to many, especially new users. And this is even a (overly) simplified use case. Try putting in the display of some validation messages there;)
This issue is similar to #5489, but it is a very different use-case.
It makes way more sense to transclude the scope with the dom element instead. If a new scope is really needed a user can put an ngController on the ngTransclude element anyway. Or there can be an optional flag on ngTransclude that triggers one. That flag can be used to solve the #5489 use case too.

Closing comment (2014-08-15T11:18:55Z): @SanderElias you are right that #5489 suggest that the transcluded scope should be the same as an isolated scope (I don't think it should work like this) but the rest of this issue goes into discussion about the best treatment of transcluded scopes and as such I think we should use it to centralise the discussion.
I'm closing this as duplicate of  #5489 but I totally agree with your arguments - transclusion scopes are surprising for many people so let's try to think of alternatives in #5489