9

在以下情况下如何使用嵌入。目的是在 html(部分)文件中使用标记,而不是在模板中定义它(在指令内)。

我在这里找到了一个很棒的树指令。(来源)原文:http: //jsfiddle.net/n8dPm/

我没有在指令中定义模板,而是尝试使用嵌入的内容。我还将 Angular 更新为 1.2.0.rc2。更新:http: //jsfiddle.net/aZx7B/2/

得到以下错误

TypeError:对象 [object Object] 的属性“$transclude”不是函数

代码:

module.directive("tree", function($compile) {
    return {
        restrict: "E",
        transclude: true,
        scope: {family: '='},
        template:       
            '<ul>' + 
                '<li ng-transclude></li>' +
                '<li ng-repeat="child in family.children">' +
                    '<tree family="child"></tree>' +
                '</li>' +
            '</ul>',
        compile: function(tElement, tAttr) {
            var contents = tElement.contents().remove();
            var compiledContents;
            return function(scope, iElement, iAttr) {
                if(!compiledContents) {
                    compiledContents = $compile(contents);
                }
                compiledContents(scope, function(clone, scope) {
                         iElement.append(clone); 
                });
            };
        }
    };
});

<div ng-app="myapp">
    <div ng-controller="TreeCtrl">
        <tree family="family">
            <p>{{ family.name }}</p>
        </tree>
    </div>
</div>

编辑:

在大卫的建议下,做了一些改动。http://jsfiddle.net/aZx7B/3/ 现在,它打印出来了,家长。改变,family- >treeFamily虽然没有工作

4

3 回答 3

8

您还需要在模板中输出家庭的名称:http: //jsfiddle.net/roadprophet/DsvX6/

module.directive("tree", function($compile) {
    return {
        restrict: "E",
        transclude: true,
        scope: {family: '='},
        template:       
            '<ul>' + 
                '<li ng-transclude></li>' +
                '<li ng-repeat="child in family.children">' +
                    '<tree family="child">{{family.name}}</tree>' +
                '</li>' +
            '</ul>',
        compile: function(tElement, tAttr, transclude) {
            var contents = tElement.contents().remove();
            var compiledContents;
            return function(scope, iElement, iAttr) {
                if(!compiledContents) {
                    compiledContents = $compile(contents, transclude);
                }
                compiledContents(scope, function(clone, scope) {
                         iElement.append(clone); 
                });
            };
        }
    };
});

编辑

您也可以通过这样做来简化:http: //jsfiddle.net/roadprophet/DsvX6/2/

<div ng-app="myapp">
    <div ng-controller="TreeCtrl">
        <tree family="treeFamily">           
        </tree>
    </div>
</div>


module.directive("tree", function($compile) {
    return {
        restrict: "E",
        transclude: true,
        scope: {family: '='},
        template:       
            '<ul>' + 
                '<li ng-transclude></li>' +
                '<p>{{ family.name }}</p>' + 
                '<li ng-repeat="child in family.children">' +
                    '<tree family="child"></tree>' +
                '</li>' +
            '</ul>',
        compile: function(tElement, tAttr, transclude) {
            var contents = tElement.contents().remove();
            var compiledContents;
            return function(scope, iElement, iAttr) {
                if(!compiledContents) {
                    compiledContents = $compile(contents, transclude);
                }
                compiledContents(scope, function(clone, scope) {
                         iElement.append(clone); 
                });
            };
        }
    };
});

编辑 虽然问题的相同来源。没有模板被传递给内部树指令。 http://jsfiddle.net/roadprophet/DsvX6/3/

<div ng-app="myapp">
    <div ng-controller="TreeCtrl">
        <tree family="treeFamily">           
                <p>{{ family.name }}</p>
        </tree>
    </div>
</div>

 template:       
            '<ul>' + 
                '<li ng-transclude></li>' +
                '<li ng-repeat="child in family.children">' +
                    '<tree family="child"><div ng-transclude></div></tree>' +
                '</li>' +
            '</ul>'
于 2013-10-03T19:21:04.227 回答
1

您想针对范围编译转入的 DOM;$transclude您可以使用指令控制器定义中的可注入函数自动执行此操作:

module.directive("tree", function($compile) {
  return {
    restrict: "E",
    transclude: true,
    scope: { family: '=' },
    template: '<ul>' + 
                '<li ng-repeat="child in family.children">' +
                  '<tree family="child">' +
                    '<p>{{ child.name }}</p>' +
                  '</tree>' +
                '</li>' +
              '</ul>',
    controller: function($element, $transclude) {
      $transclude(function(e) {
        $element.append(e);
      });
    },
    compile: function(tElement, tAttr, transclude) {
      var contents = tElement.contents().remove();
      var compiledContents;
      return function(scope, iElement, iAttr) {
        if(!compiledContents) {
          compiledContents = $compile(contents);
        }
        compiledContents(scope, function(clone) {
          iElement.append(clone);
        });
      };
    }
  };
});

这允许您在根模板中使用范围属性(还要注意上面指令模板中的使用):treeFamilychild

<div ng-app="myapp">
  <div ng-controller="TreeCtrl">
    <tree family="treeFamily">
      <p>{{ treeFamily.name }}</p>
    </tree>
  </div>
</div>

你可以在这里看到一个例子:http: //jsfiddle.net/BinaryMuse/UzHeW/

于 2013-10-03T20:08:34.343 回答
0

晚会很晚了。我在一个项目中需要这个,所以在深入研究它并找到其他很好的方法和方向之后,最终想出了这个:

与指令相同的代码ng-transclude,但添加了少量context绑定,指令在每次更改时监视并设置在嵌入的生成范围上。与此相同ng-repeat,但这允许:

  1. 将自定义 ng-transclude 与 ng-repeat 一起使用,无需重写 ng-repeat 和类似 angular/2 模板出口的麻烦。
  2. 让嵌入的内容在从父级接收直接上下文数据的同时继续访问祖父级范围。再次与模板插座相同。

增强的 ng-transclude 函数:

return function ngTranscludePostLink(
   ...
  ) {
  let context = null;
  let childScope = null;
  ...
  $scope.$watch($attrs.context, (newVal, oldVal) => {
    context = newVal;
    updateScope(childScope, context);
  });
  ...
  $transclude(ngTranscludeCloneAttachFn, null, slotName);
  ...
  function ngTranscludeCloneAttachFn(clone, transcludedScope) {
     ...                                 
     $element.append(clone);
     childScope = transcludedScope;
     updateScope(childScope, context);
     ...
  }
  ...
  function updateScope(scope, varsHash) {
    if (!scope || !varsHash) {
      return;
    }
    angular.extend(scope, varsHash);
  }
}

它的用法:

应用程序

<my-list items="$ctrl.movies">
   <div>App data: {{ $ctrl.header }}</div>
   <div>Name:{{ name }} Year: {{ year }} Rating: {{ rating 
          }}</div>
</my-list>

我的列表

<ul>
  <li ng-repeat="item in $ctrl.items track by item.id">
   <div>Ng repeat item scope id: {{ $id }}</div>
   <cr-transclude context="item"></cr-transclude>
  </li>
</ul>

完整的指令代码可以在 GitHub 上找到

于 2020-10-06T21:37:56.537 回答