javascript - 包含指令的指令不使用指令范围,即使特别告知

标签 javascript angularjs

我正在使用一个包含指令,它本身正在使用一个 Controller ,它应该重新定义内部范围,但事实并非如此。而且无论我使用多少技巧,我似乎都无法完成这件事(让我相信我做错了什么)。

代码简化为一个简单的案例,如下所示:

HTML:

<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl">
  <mydirective>

    {{foo}}

  </mydirective>
</body>
</html>

JavaScript:

angular.module('app', [])

.controller('MainCtrl', function($scope) {
  $scope.foo = 'bar';
})
.controller('InDirectiveController', function($scope) {
  $scope.foo = 'baz';
})

.directive('mydirective', function() {
  return {
    restrict: 'EA',
    scope: false,
    template:'<div ng-controller="InDirectiveController">'+
                     '{{foo}} <inside></inside>'+
              '</div>',
    transclude:true,
    link: function(scope, element, attrs, ctrl, transclude) {

      transclude(scope, function(clone, scope) {
        element.find("inside").append(clone);
      });
    }
  };
});

例子在这里

http://jsbin.com/wuqoqalenu/1/edit?html,js,output

我希望输出是“baz baz”,因为我专门使用了 transclude 函数。但是,它实际上是“baz bar”,我不确定如何强制嵌入代码的范围使用我在 Controller 中设置的范围。

最佳答案

在没有 replace:true 的情况下,您基本上会得到指令 HTML 的以下内容(编译前)

<mydirective>
    <div ng-controller="InDirectiveController">
        {{foo}} <inside></inside>
    </div>
<mydirective>

编译时,指令作用域与外部 (MainCtrl) 作用域保持相同,因此嵌入的内容将根据该作用域进行评估。因此第一个 {{foo}} 是“baz”(来自 InDirectiveController),嵌入的内容 {{foo}} 是“bar”(来自 MainCtrl)。

使用 replace:true,编译指令 HTML 变为:

<div ng-controller="InDirectiveController">
    {{foo}} <inside></inside>
</div>

当 Angular 编译它时,ng-controller 会创建一个新的作用域,它继承自 MainCtrl 的作用域,它与指令的 DOM 节点相关联,因此它成为指令的作用域。因此,当您执行嵌入时,它现在正在使用 InDirectiveController 的范围,因此您会得到“baz baz”。

更新以解决评论中的问题:

指令并不总是创建新的范围。当你使用

scope: false

指令范围将与“外部范围”相同。因此,当指令的链接函数运行时,它将是“外部范围”。

transclude 函数使用作为第一个参数传递的范围作为被嵌入内容的范围。在您的第一个示例中,此范围是传递给链接函数的范围,在第一种情况下将是“外部范围”。

当您设置 replace: true 时,这仍然不会导致创建新范围。但是,您的模板在其外部元素上使用 ng-controller。 Angular 通过“向下”遍历 DOM 进行编译,并通过向上遍历进行链接。所以它编译指令,然后编译模板,然后链接模板(调用 ngController 的链接函数创建一个新的范围),然后指令的链接函数与指令的模板元素的范围,现在是创建的范围ng-controller(而不是“外部范围”)。

更新:没有 mg-controller 的指令实现

.directive('mydirective', function() {
  return {
    restrict: 'EA',
    scope: true,
    controller: function($scope) {
       $scope.foo = 'baz';
    },
    template:'<div>'+
                     '{{foo}} <inside></inside>'+
              '</div>',
    transclude:true,
    link: function(scope, element, attrs, ctrl, transclude) {

      transclude(scope, function(clone, scope) {
        element.find("inside").append(clone);
      });
    }
  };
});

关于javascript - 包含指令的指令不使用指令范围,即使特别告知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30408170/

相关文章:

javascript - 复制模块后无法读取未定义的属性 'visitExpression'

javascript - 检查输入是否与 ul 中的值重复

javascript - 如何将焦点设置在 ng-repeat 生成的下一个输入字段上?

angularjs - 使用 ng-options 和数组作为值进行选择

javascript - AngularJs $routeProvider 不支持 MVC

javascript - Javascript/Jquery 监听器

javascript - 滚动条出现在滚动条上

javascript - 如何连续使用两个 Twitter Bootstrap 模式?

angularjs - Node.js 中的大文件下载失败

javascript - Angular 数据绑定(bind) - 手动设置模型值