无法从指令访问控制器作用域

11

这是我的应用程序配置:

angular.module('myApp', ['myApp.directives', 'myApp.controllers', 'myApp.services']);

这是我的控制器:

angular.module('myApp.controllers', [])
  .controller('MainCtrl', function ($scope) {
      $scope.name = 'world';
  });

这是我的指令:

var directives = angular.module('myApp.directives', []);

directives.directive("hello", function () {
    return function (scope, elm, attrs) {
        elm.text("hello, " + scope[attrs.name]);
    };
});

这是我的 HTML 代码:

<div ng-controller="MainCtrl">
    <h1 hello></h1>
</div>

问题在于angular将指令呈现为:

你好,未定义

而不是:

你好,世界

有什么问题吗?

4个回答

7
您正在访问 scope[attrs.name],但指令没有为属性 name 提供值。
有两个选项:
  1. 将指令更改为 elm.text("hello, " + scope['name']); 这不是首选方式,因为它硬编码到作用域属性名称

  2. 将html更改为 <h1 hello name="name"></h1>。这更好,但我认为它使用了冗余属性

我建议您将指令更改为 elm.text("hello, " + scope[attrs['hello']]); 甚至更好的方法是 elm.text("hello, " + scope.$eval(attrs['hello'])); 这样你也可以获得表达式的好处(例如:<h1 hello="name | uppercase"></h1>演示 这样html就会变成 <h1 hello="name"></h1> 关于attrs参数:它只是从存在于dom元素上的属性中获取的字符串映射。

@vcardillo 好的,添加 Plunker 或者提出问题吧 :) - Liviu T.
调试后,我意识到我的问题在于我在指令定义对象中使用了 scope: {...} 属性,从而创建了一个新的隔离作用域。这样做会阻止原型继承。 - vcardillo

6

在编写本文时,你可以做一些似乎没有记录在Angular文档中的事情(请参见Mark Rajcok在此处的评论:http://docs.angularjs.org/api/ng.$rootScope.Scope)。

从你的指令内部:

scope.$parent.name

如果您在指令内部使用console.log(scope)打印指令的scope,您将看到这些属性。
所有这些都说了,我不知道这是否是“正确”的Angular约定,因为它既没有文档记录,也没有其他更好的关于如何访问指令所在控制器的文档记录。

3

您可以使用scope进行访问。请查看http://jsfiddle.net/rPUM5/

directives.directive("hello", function () {
    return function (scope, elm, attrs) {
        elm.text("hello, " + scope.name);
    };
});​

这真的很有趣,谢谢!我发现关于使用点语法的文档非常少,就像你所做的那样。 - vcardillo
3
这真的是错误的,传递给连接函数的 scope 对象并不是控制器实例化的 $scope,而是一个只读引用,指向指令实例化的作用域,应该用 scope 表示。 - fiatjaf
1
谁说它们是一样的?你不可能只通过写 $scope 来访问 $scope。这违反了惯例。在 scope 前面加上 $ 并不意味着它是控制器的 scope 对象。 - Mahbub

1
我发现另一个情况: 如果您正在访问来自Ajax请求正文的变量,则必须等待变量设置。

e.g:

# in controller
$http.get('/preview').then( (response) ->
  $scope.tabs = response.data.tabs
  $scope.master_switch = '1'
  console.info 'after get response in controller'
)

# in directive
directive('masterSwitch', ->
  (scope, element, attrs) ->
    alert 'in directive!'   # will show before "after get response in controller"
    console.info scope.master_switch  # is undefined
    setTimeout( -> console.info(scope.master_switch), 50) # => 1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接