Почему нельзя получить доступ к $ rootScope в шаблоне директивы с изолированной областью?

81

С изолированной областью видимости шаблон директивы, похоже, не может получить доступ к переменной контроллера ('Ctrl') $ rootScope, которая, однако, присутствует в контроллере директивы. Я понимаю, почему переменная $ scope контроллера ('Ctrl') не видна в изолированной области.

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: {},
camden_kid
источник
Вы пробовали ввести $ rootScope в директиву ... directive('myTemplate', function($rootScope) { ... })?
Марк Клайн
@MarcKline Просто попробовал и не повезло.
camden_kid
1
Есть ли причина, по которой использование услуги недостаточно для ваших целей?
Марк Клайн
1
@Kalyan - я лично считаю, что $ rootScope следует использовать только для событий, а Factory для передачи данных в директивы. Одна из причин заключается в том, что использование $ rootScope похоже на использование глобальных переменных, что не идеально. Кроме того, Factory может быть четко определенной оболочкой, которая может быть расширена позже.
camden_kid

Ответы:

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» и о том, что его можно использовать таким образом). Однако я бы предположил, что ответ Марка Клайна в целом является лучшим решением.
camden_kid
5
удивительный! очень полезно знать, что $ rootScope превращается в $ root в представлениях, большое спасибо!
Cris R
Это идеально, так как мне нужно было получить доступ к функции, определенной в rootScope
Альфредо А.
Хороший. Здесь тоже работает. Не могли бы вы объяснить, почему $ 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 Большое спасибо за это и за то, что указали мне правильное направление того, чего я пытаюсь достичь. Я думаю, что ответ Нидиш Кришнана следует принять как «ответ» по причине, изложенной в моем комментарии.
camden_kid
1
+1 для случая использования констант, поскольку они используются редко. Также советом было не использовать $ rootScope.
Farzad YZ
23

1) Из-за изолированной области действия $scopeв вашем контроллере Ctrl и контроллер директивы не относятся к одной и той же области - допустим, у нас есть область действия 1 в Ctrl и область 2 в директиве.

2) Из-за изолированного объема 2 прототипно не наследуется от $rootScope; поэтому, если вы определите, $rootScope.blahнет никаких шансов, что вы сможете увидеть это в scope2 .

3) В шаблоне директивы вы можете получить доступ к scope2

Если резюмировать, вот схема наследования

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


$rootScope.blah
> "Hello"
scope1.blah
> "Hello"
scope2.blah
> undefined
Томас Гиллори
источник
1
Очень полезно, но обходной путь nidhishkrishnan действительно работает, если каким-то образом необходимо использовать значения rootScope. Хороший взлом.
Марк Клайн
1
Что ж, то, что вы сказали, является логикой, чтобы ответить, почему я не могу использовать переменные $ rootScope в html (без $ root.), Но когда я использую плагин Batarang для просмотра $ scopes, я ясно вижу, что $ rootScope - это родительская область $ всех остальных (включая изолированную область в директивах). Кроме того, определение из официальных документов angular гласит: «Каждое приложение имеет одну корневую область видимости. Все остальные области являются дочерними областями корневой области» ( docs.angularjs.org/api/ng/service/$rootScope )
IsraGab
1

Я знаю, что это старый вопрос. Но это не удовлетворило мою инквизицию о том, почему изолированная область не сможет получить доступ к свойствам в $ rootcope.

Итак, я покопался в 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 всякий раз, когда создается новая область видимости. Здесь ясно, что любая изолированная область видимости не наследует прототипом rootcope. скорее только корневая область добавляется как свойство «$ root» в новую область. Таким образом, мы можем получить доступ к свойствам rootcope только из свойства $ root в новой изолированной области.

Адарш Шарма
источник