将 $properties 添加到 Transcluded 范围

Adding $properties to Transcluded Scope

我有一个带有嵌入范围的指令,如下所示:

<my-control>
    Some Content: {{value}}
</my-control>

其中 value 来自父范围。

我想添加一个与控件作用域交互的函数,所以我可以这样做:

<my-control>
    Some Content: {{value}}
    <button ng-click="$close()">Close</button>
</my-control>

类似于 ngRepeat$index 等属性添加到行范围的方式。在我的指令中执行此操作的最简单方法是什么?

您可以在您的指令链接函数中将新方法附加到您的范围(如果您有的话,甚至可以在指令的控制器中)。

为了简单起见,我将在这里展示如何将新方法附加到指令的链接函数:

app.directive('myControl', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: '<div ng-transclude></div>',
        link: function postLink(scope) {
            scope.$close = function close() {
                console.log("Close function that lives in directive...");
            };
        }
    };
});

在您的 HTML 中,您应该能够简单地调用该函数:

<my-control>
    Click <a href ng-click="$close();">close</a> things.
</mycontrol>

也想用上面的例子在实践中检查这个 plunker: http://plnkr.co/edit/SPSFGcB49qXmXROmNeHj?p=preview

希望这对您有所帮助,如果我遗漏了什么,请随时告诉我,我很乐意提供任何其他信息。

当我们不指定 scope:true(new Scope) 或 scope:{} (isolatedScope) 并且当我们重新使用该指令时,在范围上定义的属性将被覆盖。

例如:

<div ng-controller="AppCtrl">
    <my-control name="myControl1">
        Some Content: {{value}} 
        My Control Name: {{name}}
    </my-control>
    <my-control name="myControl2">
        Some Content: {{value}} 
        My Control Name: {{name}}
    </my-control>
</div>

它不会在屏幕上同时打印 myControl1myControl2,而是会打印两次 myControl2

Plnkr

要解决此问题,请尝试以下任一解决方案。

解决方案1

transclde:true 将创建一个新范围。在此范围而不是指令的范围内设置属性。

app.directive('myControl', function() { 
  return {
    restrict: 'E',
    transclude: true,
    template: '<div><p><strong>Welcome to the testMe directive!</strong></p> <div ng-transclude></div></div>',
    link: function(scope, element, attrs) {
      var transclusionTarget = element[0].querySelector('[ng-transclude]').firstChild;
      var transclusionScope = angular.element(transclusionTarget).scope();
      transclusionScope.name = attrs.name;
    }
  }
});

此处 ng-transclude div 下的元素将使用 transclusionScope 进行编译,获取它并更新其中的属性。

Plnkr

解决方案2 不使用 ng-transclude,而是手动嵌入内容。

app.directive('myControl', function() {  
  return {
    restrict: 'E',
    transclude: true,
    template: '<div><p><strong>Welcome to the testMe directive!</strong></p> <div transclude-target></div></div>',
    link: function(scope, element, attrs, directiveCtrl, transcludeFn ) {

      var transclusionScope = scope.$new(),
          transclusionTarget = element[0].querySelector('[transclude-target]');

      transclusionScope.name = attrs.name;

      transcludeFn(transclusionScope, function (clone) {
        angular.element(transclusionTarget).append(clone);
      });
    }
  }
});

在这里,创建一个 new Scope 使用 scope.$new() 扩展指令的范围。并更新其中的属性。

Plnkr

解决方案 1 可能并非在所有情况下都有效。当我们访问 firstChild 时,如果它还没有准备好 Solution1 将失败 .

解决方案 2 更简洁,适用于所有情况。

Vinay 的回答是正确的,但我会对其进行一些改动以使其更加 "Angular"

公开指令 API 的 "angular" 方法是通过控制器。我会遵循 ngForm 指令使用的模式 -

像这样:

app.directive('myControl', function() {  
  return {
    restrict: 'E',
    transclude: true,
    controller: function($scope) {
        this.$close = function(){
            //close me
        }
        this.$open = function() {
            //open me
        }

    }
    template: '<div><p><strong>Welcome to the testMe directive!</strong></p> <div transclude-target></div></div>',
    link: function(scope, element, attrs, directiveCtrl, transcludeFn ) {

      transcludeFn(scope.$new(), function (clone, transclusionScope) {
         //only expose the API to the scope if the name attribute is present
          if(attrs.name) {
              transclusionScope[name] = directiveCtrl;
          }
          angular.element(element[0].querySelector('[transclude-target]').append(clone);
      });
    }
  }
});

与用法:

 <my-control name="myControl2">
    <button ng-click="myControl2.$close()>Close</button>
 </my-control>