为什么不能在具有独立作用域的指令模板中访问$ rootScope?


81

使用隔离范围,伪指令的模板似乎无法访问控制器('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) { ... })
2014年

@MarcKline只是尝试了,没有运气。
camden_kid 2014年


1
使用服务不足以达到您的目的是有原因的吗?
马克·克莱恩

1
@Kalyan-我个人认为$ rootScope应该仅用于事件,而Factory仅用于将数据传递给指令。原因之一是使用$ rootScope就像使用不理想的全局变量一样。同样,工厂可以是定义明确的包装器,可以在以后进行扩展。
camden_kid 2014年

Answers:


164

您可以尝试使用以下方法 $root.blah

工作守则

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

6
我将其标记为答案,因为它“解决了”我想要实现的目标(我不知道“ $ root”或它可以像这样使用)。但是,我建议Mark Kline的答案通常是最好的解决方案。
camden_kid 2014年

5
惊人!知道$ rootScope会在视图中更改为$ root,这非常有用,非常感谢!
Cris R

这是完美的,因为我需要做的是访问rootScope
Alfredo A.

好一个 它也在这里工作。您能解释一下为什么$ root而不是$ rootScope吗?我还注入了$ rootScope,但在函数调用时未定义。
Unknown_Coder

32

通常,应避免使用$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;
})

这是您的Fiddle的一个分支,展示了您可能如何使用


3
+1非常感谢,并为我要达到的正确方向指明了方向。我认为,NidhishKrishnan的答案应作为我的评论中所述的“答案”。
camden_kid 2014年

1
+1用于常量的用例,因为它们很少使用。另外,有关不使用$ rootScope的说明也是一个提示。
Farzad YZ

23

1)由于的分离范围$scope在控制器Ctrl键并在指令控制器没有指向同一个范围-让我们说我们有scope1 Ctrl键和scope2的指令。

2)由于隔离范围scope2 原型地继承$rootScope;因此,如果您定义$rootScope.blah,就没有机会在scope2中看到它。

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

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

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


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

1
非常有用,但是如果需要使用rootScope值,nidhishkrishnan的解决方法确实可以工作。这是一个不错的技巧。
马克·克莱恩

1
好吧,您所说的是为了回答为什么我不能在html中使用$ rootScope变量(没有$ root)的逻辑,但是当我使用Batarang插件查看$ scopes时,我可以清楚地看到$ rootScope是所有其他父级的$ scope(包括指令中的隔离范围)。此外,从官方的角度文档定义说:“每个应用程序都有一个根范围内的所有其他范围是根范围内的后裔范围。”(docs.angularjs.org/api/ng/service/$rootScope
IsraGab

1

我知道这是一个老问题。但这并不能满足我的询问,为什么孤立的作用域将无法访问$ rootscope中的属性。

所以我挖了角形库,发现-

$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调用。显然,任何隔离范围都不是原型继承的rootscope。而是只有rootscope被添加为新作用域中的属性“ $ root”。因此,我们只能从新的隔离范围中的$ root属性访问rootscope的属性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.