【问题标题】:Why can't the $rootScope be accessed in the template of a directive with isolate scope?为什么不能在具有隔离范围的指令的模板中访问 $rootScope?
【发布时间】:2014-05-11 17:40:59
【问题描述】:

使用隔离作用域,指令模板似乎无法访问控制器 ('Ctrl') $rootScope 变量,但该变量确实出现在指令的控制器中。我明白为什么控制器 ('Ctrl') $scope 变量在隔离范围内不可见。

HTML:

<div ng-app="app">
    <div ng-controller="Ctrl">
        <my-template></my-template>
    </div>

    <script type="text/ng-template" id="my-template.html">
        <label ng-click="test(blah)">Click</label>
    </script>
</div>

JavaScript:

angular.module('app', [])
    .controller('Ctrl', function Ctrl1($scope,  $rootScope) {
        $rootScope.blah = 'Hello';
        $scope.yah = 'World'
    })
    .directive('myTemplate', function() {
        return {
            restrict: 'E',
            templateUrl: 'my-template.html',
            scope: {},
            controller: ["$scope", "$rootScope", function($scope, $rootScope) {
                console.log($rootScope.blah);
                console.log($scope.yah);,

                $scope.test = function(arg) {
                    console.log(arg);
                }
            }]
        };
    });

JSFiddle

在没有隔离范围的情况下访问该变量 - 可以通过注释隔离范围行看出:

        // scope: {},

【问题讨论】:

  • 您是否尝试过将 $rootScope 注入指令中...directive('myTemplate', function($rootScope) { ... })
  • @MarcKline 刚刚尝试过,但没有成功。
  • 是否有理由说明使用服务不足以满足您的目的?
  • @Kalyan - 我个人认为 $rootScope 应该只用于事件和工厂用于将数据传递给指令。一个原因是使用 $rootScope 就像使用不理想的全局变量一样。此外,工厂可以是定义明确的包装器,可以在以后扩展。

标签: javascript angularjs angularjs-directive


【解决方案1】:

您可以使用$root.blah 尝试这种方式

Working Code

html

 <label ng-click="test($root.blah)">Click</label>

javascript

  angular.module('app', [])
    .controller('Ctrl', function Ctrl1($scope,  $rootScope) {
        $rootScope.blah = 'Hello';
        $scope.yah = 'World'
    })
    .directive('myTemplate', function() {
        return {
            restrict: 'E',
            templateUrl: 'my-template.html',
            scope: {},
            controller: ["$scope", "$rootScope", function($scope, $rootScope) {
                console.log($rootScope.blah);
                console.log($scope.yah);

                $scope.test = function(arg) {
                    console.log(arg);
                }
            }]
        };
    });

【讨论】:

  • 我将此标记为答案,因为它“解决”了我想要实现的目标(我不知道“$root”或者它可以像这样使用)。 但是,我建议 Mark Kline 的回答通常是最好的解决方案。
  • 太棒了!知道 $rootScope 在视图中更改为 $root 非常有用,非常感谢!
  • 这很完美,因为我需要做的是访问 rootScope 中定义的函数
  • 好一个。它也在这里工作。你能解释一下为什么用 $root 而不是 $rootScope 吗?我也注入了 $rootScope 但它在函数调用时未定义。
【解决方案2】:

通常,您应该避免使用$rootScope 来存储您需要在控制器和指令之间共享的值。这就像在 JS 中使用全局变量。改用服务:

一个常数(或值...使用类似):

.constant('blah', 'blah')

https://docs.angularjs.org/api/ng/type/angular.Module

工厂(或服务或供应商):

.factory('BlahFactory', function() {
    var blah = {
        value: 'blah'
    };

    blah.setValue = function(val) {
      this.value = val;
    };

    blah.getValue = function() {
        return this.value;
    };

    return blah;
})

这是一个fork of your Fiddle,演示了您可以如何使用其中一个

【讨论】:

  • +1 非常感谢这一点,并为我努力实现的目标指明了正确的方向。我认为 NidhishKrishnan 的答案应该被接受为我评论中所述的原因。
  • +1 用于常量的用例,因为它们很少使用。此外,关于不使用 $rootScope 的注释也是一个专业提示。
【解决方案3】:

1) 由于控制器 Ctrl 和指令控制器中的隔离范围 $scope 不引用相同的范围 - 假设我们在 Ctrl 和 scope2 中有 scope1 在指令中。

2) 由于隔离范围 scope2 原型继承自 $rootScope ;所以如果你定义了$rootScope.blah,你就不可能在scope2中看到它。

3) 您可以在指令模板中访问的是 scope2

如果我总结一下,这里是继承模式

    _______|______
    |            |
    V            V
$rootScope     scope2
    |
    V
  scope1


$rootScope.blah
> "Hello"
scope1.blah
> "Hello"
scope2.blah
> undefined

【讨论】:

  • 非常有帮助,但如果需要以某种方式使用 rootScope 值,nidhishkrishnan 的解决方法确实有效。这是一个不错的技巧。
  • 嗯,你说的是逻辑,为了回答为什么我不能在html中使用$rootScope变量(没有$root。),但是当我使用Batarang插件看到$范围,我可以清楚地看到 $rootScope 是所有其他范围的父 $scope(包括指令中的隔离范围)。此外,角度官方文档的定义说:“每个应用程序都有一个根范围。所有其他范围都是根范围的后代范围”(docs.angularjs.org/api/ng/service/$rootScope
【解决方案4】:

我知道这是一个老问题。但这并不能满足我对隔离作用域为何无法访问 $rootscope 中的属性的询问。

所以我在 angular lib 中挖掘并发现 -

$new: function(isolate) {
  var ChildScope,
      child;

  if (isolate) {
    child = new Scope();
    child.$root = this.$root;
    child.$$asyncQueue = this.$$asyncQueue;
    child.$$postDigestQueue = this.$$postDigestQueue;
  } else {

    if (!this.$$childScopeClass) {
      this.$$childScopeClass = function() {
        // blah blah...
      };
      this.$$childScopeClass.prototype = this;
    }
    child = new this.$$childScopeClass();
  }

这是每当创建新范围时 angular 调用的函数。很明显,任何孤立的范围都不是原型继承根范围。而是仅将根作用域作为属性“$root”添加到新作用域中。所以我们只能从新的隔离作用域中的$root属性访问rootscope的属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多