Чому не можна отримати доступ до $ rootScope у шаблоні директиви з ізоляцією?


81

Зі сферою ізоляції шаблон директиви, здається, не може отримати доступ до змінної $ rootScope контролера ('Ctrl'), яка, однак, відображається в контролері директиви. Я розумію, чому змінну $ 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: {},

Ви пробували вводити $ 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;
})

Ось вилка вашої скрипки, яка демонструє, як ви можете використовувати будь-яку з них


3
+1 Щиро дякую за це і за те, що я направив мене у правильному напрямку до того, чого я намагаюся досягти. Я думаю, що NidhishKrishnan слід прийняти як "відповідь" з причини, зазначеної в моєму коментарі.
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 - це батьківська область $ всіх інших (включаючи ізольовану область в директивах). Крім того, у визначенні з кутових офіційних документів сказано: "Кожна програма має єдину кореневу область. Усі інші області є нащадками області кореневої області" ( docs.angularjs.org/api/ng/service/$rootScope )
IsraGab

1

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

Тож я зарився в кутову лібу і виявив -

$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 у новому ізольованому полі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.