1

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

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

value来自父范围的地方。

我想添加一个与控件范围交互的函数,所以我可以做这样的事情:

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

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

4

3 回答 3

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

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

于 2015-03-20T20:39:19.103 回答
1

当我们没有指定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>

它不会同时在屏幕上打印,而是打印myControl1两次。myControl2myControl2

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;
    }
  }
});

在这里,div 下的元素ng-transclude将使用 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 更干净,适用于所有情况。

于 2015-03-22T05:14:25.343 回答
0

维奈的回答是正确的,但我会对其进行修改以使其更加“有角度”

暴露指令 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>
于 2015-03-24T17:02:29.103 回答