AngularJS:我可以在指令中使用transcluded内容而无需重新定义控制器吗?

时间:2014-02-28 10:50:37

标签: angularjs angularjs-directive

我有一个标签控件,可以根据所选标签显示或隐藏控件中的内容。

这很好用,但是选项卡窗格的内容开始与范围奇怪地表现。在转换内容中引用范围似乎不再引用已定义的控制器范围。

这可以通过任何已经转换内容的指令来看出。鉴于具体的控制器:

app.controller("MainCtrl", function ($scope) {
  $scope.getTestText = function () {
    alert($scope.testText);
    alert(this.testText);
  }
});

在以下标记中使用:

<h1>Outside Tab</h1>
<div>
    <input type="text" ng-model="testText" />
    <button ng-click="testText = 'outside'">Set Test Text</button>
    <button ng-click="getTestText()">Get Test Text</button>
    {{testText}}
</div>

<simple-directive>
  <h1>Inside Directive</h1>
  <div>
      <input type="text" ng-model="testText" />
      <button ng-click="testText = 'inside'">Set Test Text</button>
      <button ng-click="getTestText()">Get Test Text</button>
      {{testText}}
  </div>
</simple-directive>

请参阅this plunker

如果单击顶部的“设置测试文本”按钮,然后单击“获取测试文本”按钮,则两个警报显示相同的内容(“外部”)。如果单击第二个“设置测试文本”按钮然后“获取测试文本”,则会有不同的结果:虽然“this”具有预期的“inside”值,但范围上的值仍然是“在外部”。

一种解决方法是在已转换内容中定义控制器,如下所示:

<simple-directive>
  <h1>Inside Directive</h1>
  <div ng-controller="MainCtrl">
      <input type="text" ng-model="testText" />
      <button ng-click="testText = 'inside'">Set Test Text</button>
      <button ng-click="getTestText()">Get Test Text</button>
      {{testText}}
  </div>
</simple-directive>

但如果可能,我宁愿避免这种情况。

所以我的问题是:有没有更好的方法来做到这一点,不会改变范围?这只是预期的行为吗?

1 个答案:

答案 0 :(得分:2)

ngTransclude创建一个子(非隔离)范围:

enter image description here

$ transclude函数默认创建一个新的子范围source code

transcludedScope = scope.$new();

最好的解决方案是避免引用范围上的原语:

为什么不使用原语?看到类似的答案...

演示插件:http://plnkr.co/edit/LuU6ard1JYsYCOvlP5iY?p=preview

app.controller("MainCtrl", function ($scope) {
  $scope.test = {};
  $scope.getTestText = function () {
    alert($scope.test.text);
    alert(this.test.text);
  }
});

<强>模板:

<input type="text" ng-model="test.text" />
<button ng-click="test.text = 'inside'">Set Test Text</button>
<button ng-click="getTestText()">Get Test Text</button>
{{test.text}}

另一种解决方案是手动转换而不创建新的子范围:

app.directive('simpleDirective', function () {
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        scope: {},
        link: function(scope,elm,attrs,ctrl,$transclude){
          $transclude(scope.$parent, function(clone){
            elm.after(clone);
          })
        }
    };
})