Transclusion and scopes in angular: Why is this not working?

匆匆过客 提交于 2019-12-20 03:47:30

问题


I have a very simple setup:

<pane title="mytitle">Title in parent (transcluded): {{title}}</pane>

and

angular.module('transclude', [])
 .directive('pane', function(){
    return {
      restrict: 'E',
      transclude: true,
      scope: { title:'@' },
      template: '<div>' +
                  '<div>Title in isolated scope: {{title}}</div>' +
                  '<div ng-transclude></div>' +
                '</div>'
    };
});

The plunker is here: http://plnkr.co/edit/yRHcNGjQAq1NHDTuwXku

The transclusion itself is working but the {{title}} only gets replaced in the directive's template.
The {{title}} inside the transcluded element however stays empty even though the directive has a variable title in its scope. Why is that?


回答1:


The scope of the transcluded element is not a child scope of the directive but a sibling one. This is what documentation says:

In a typical setup the widget creates an isolate scope, but the transclusion is not a child, but a sibling of the isolate scope.

The simplest solution in this case how you can access transcuded scope is like this:

.directive('pane', function () {
    return {
        restrict: 'E',
        transclude: true,
        scope: {
            title: '@'
        },
        template:
            '<div>' +
                '<div>Title in isolated scope: {{title}}</div>' +
                '<div ng-transclude></div>' +
            '</div>',
        link: function (scope, element, attrs) {
            scope.$$nextSibling.title = attrs.title;
        }
    };
});

Demo: http://plnkr.co/edit/ouq9B4F2qFPh557708Q1?p=preview




回答2:


@dfsq is correct about:

The scope of the transcluded element is not a child scope of the directive but a sibling one

I'd like to add more comments why this is the expected behavior of angularJs. As the docs says:

In a typical setup the widget creates an isolate scope, but the transclusion is not a child, but a sibling of the isolate scope. This makes it possible for the widget to have private state, and the transclusion to be bound to the parent (pre-isolate) scope.

The transcluded content inside the directive is arbitrary, it should not have knowledge about the directive's isolate scope, otherwise, we would create a tight coupling code. Because for the transcluded content to work, the content must know the implementation details of your directive (what is available to use).

If you decide that the content belongs to the directive. You have 2 options:

1) Make the content part of the template

    angular.module('transclude', [])
         .directive('pane', function(){
            return {
              restrict: 'E',
              transclude: true,
              scope: { title:'@' },
              template: '<div>' +
                          '<div>Title in isolated scope: {{title}}</div>' +
                          '<div>' +
                             ' Title in parent (transcluded): {{title}} ' +
                         ' </div>' +
                        '</div>'
            };
   });

DEMO

2) Use custom tranclusion to bind the scope yourself:

angular.module('transclude', [])
     .directive('pane', function(){
        return {
          restrict: 'E',
          transclude: true,
          scope: { title:'@' },
          template: '<div>' +
                      '<div>Title in isolated scope: {{title}}</div>' +
                      '<div class="transclude"></div>' +
                    '</div>',
        link: function (scope, element, attr,controller, linker) {
           linker(scope, function(clone){
                  element.find(".transclude").append(clone); // add to DOM
           });
          }
        };
    });

DEMO



来源:https://stackoverflow.com/questions/23027254/transclusion-and-scopes-in-angular-why-is-this-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!