将$属性添加到Transcluded Scope

时间:2015-03-18 18:37:39

标签: angularjs transclusion

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

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

value来自父范围。

我想添加一个与控件范围交互的功能,所以我可以这样做:

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

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

3 个答案:

答案 0 :(得分:2)

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

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

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

我希望这会有所帮助,如果我错过任何内容,请随时告诉我,我很乐意提供任何其他信息。

答案 1 :(得分:1)

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

对于Ex:

<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

Solution1 可能无法在所有情况下使用。当我们访问firstChild并且未准备好时解决方案1将失败

Solution2 更干净,适用于所有情况。

答案 2 :(得分:0)

Vinay的回答是正确的,但我会添加一个扭曲,使其更“Angular”

公开指令API的“角度”方式是通过控制器。我将遵循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>