Warum kann in der Vorlage einer Direktive mit isoliertem Gültigkeitsbereich nicht auf $ rootScope zugegriffen werden?

81

Mit isolate scope scheint die Vorlage der Direktive nicht in der Lage zu sein, auf die Variable $ rootScope des Controllers ('Ctrl') zuzugreifen, die jedoch im Controller der Direktive angezeigt wird. Ich verstehe, warum die $ scope-Variable des Controllers ('Ctrl') im isolierten Bereich nicht sichtbar ist.

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

Auf die Variable wird ohne isolierten Bereich zugegriffen - wie aus dem Kommentar der isolierten Bereichszeile hervorgeht:

        // scope: {},
camden_kid
quelle
Haben Sie versucht, $ rootScope in die Direktive einzufügen ... directive('myTemplate', function($rootScope) { ... })?
Marc Kline
@MarcKline Hab das gerade versucht und kein Glück.
camden_kid
1
Gibt es einen Grund, warum die Nutzung eines Dienstes für Ihre Zwecke nicht ausreicht?
Marc Kline
1
@Kalyan - Ich persönlich denke, $ rootScope sollte nur für Ereignisse und Factory für die Weitergabe von Daten an Direktiven verwendet werden. Ein Grund dafür ist, dass die Verwendung von $ rootScope der Verwendung globaler Variablen gleicht, was nicht ideal ist. Eine Factory kann auch ein genau definierter Wrapper sein, der zu einem späteren Zeitpunkt erweitert werden kann.
camden_kid

Antworten:

164

Sie können diesen Weg mit ausprobieren $root.blah

Arbeitscode

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);
                }
            }]
        };
    });
Nidhish Krishnan
quelle
6
Ich markiere dies als die Antwort, da es "löst", was ich erreichen wollte (ich wusste nicht von "$ root" oder dass es so verwendet werden könnte). Allerdings würde ich vorschlagen , dass Mark Kline Antwort ist in der Regel die beste Lösung.
camden_kid
5
tolle! Es ist sehr nützlich zu wissen, dass sich $ rootScope in den Ansichten in $ root ändert, vielen Dank!
Cris R
Dies ist perfekt, da ich auf eine im rootScope definierte Funktion zugreifen musste
Alfredo A.
Gut. Es funktioniert auch hier. Können Sie bitte erklären, warum $ root anstelle von $ rootScope? Ich habe auch $ rootScope injiziert, aber es ist während des Funktionsaufrufs undefiniert.
Unknown_Coder
32

Im Allgemeinen sollten Sie vermeiden $rootScope, Werte zu speichern, die Sie zwischen Controllern und Direktiven teilen müssen. Es ist wie mit Globals in JS. Verwenden Sie stattdessen einen Dienst:

Eine Konstante (oder Wert ... Verwendung ist ähnlich):

.constant('blah', 'blah')

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

Eine Fabrik (oder ein Dienst oder ein Anbieter):

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

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

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

    return blah;
})

Hier ist eine Gabelung Ihrer Geige, die zeigt, wie Sie beide verwenden können

Marc Kline
quelle
3
+1 Vielen Dank dafür und dafür, dass Sie mir die richtige Richtung für das gezeigt haben, was ich erreichen möchte. Ich denke, NidhishKrishnan sollte aus dem in meinem Kommentar angegebenen Grund als "Antwort" akzeptiert werden.
camden_kid
1
+1 für den Anwendungsfall von Konstanten, da diese selten verwendet werden. Auch der Hinweis, $ rootScope nicht zu verwenden, war ein Pro-Tipp.
Farzad YZ
23

1) Aufgrund des isolierten Bereichs $scopein Ihrem Controller Ctrl und in der Direktive verweist Controller nicht auf denselben Bereich - sagen wir, wir haben scope1 in Ctrl und scope2 in der Direktive.

2) Wegen des isolierten Bereichs erben scope2 nicht prototypisch von $rootScope; Wenn Sie also definieren, $rootScope.blahdass es keine Chance gibt, können Sie es in scope2 sehen .

3) Auf was Sie in Ihrer Direktivenvorlage zugreifen können, ist scope2

Wenn ich es zusammenfasse, hier ist das Vererbungsschema

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


$rootScope.blah
> "Hello"
scope1.blah
> "Hello"
scope2.blah
> undefined
Thomas Guillory
quelle
1
Sehr hilfreich, aber die Problemumgehung von nidhishkrishnan funktioniert, wenn die Verwendung von rootScope-Werten erforderlich ist. Ein schöner Hack ist es.
Marc Kline
1
Nun, was Sie gesagt haben, ist Logik, um zu beantworten, warum ich $ rootScope-Variablen in HTML nicht verwenden kann (ohne $ root.), Aber wenn ich das Batarang-Plug-In verwende, um die $ Bereiche zu sehen, kann ich diese $ deutlich sehen rootScope ist der übergeordnete $ -Bereich aller anderen (einschließlich des isolierten Bereichs in Direktiven). In der Definition aus den offiziellen Winkeldokumenten heißt es außerdem: "Jede Anwendung hat einen einzelnen Stammbereich . Alle anderen Bereiche sind untergeordnete Bereiche des Stammbereichs " ( docs.angularjs.org/api/ng/service/$rootScope )
IsraGab
1

Ich weiß, dass dies eine alte Frage ist. Meine Befragung darüber, warum der isolierte Bereich nicht auf Eigenschaften im $ Rootscope zugreifen kann, wurde jedoch nicht befriedigt.

Also grub ich mich in die eckige Bibliothek und fand -

$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();
  }

Dies ist die Funktion, die von angle aufgerufen wird, wenn ein neuer Bereich erstellt wird. Hier ist klar, dass ein isolierter Bereich das Rootscope nicht prototypisch erbt. Vielmehr wird im neuen Bereich nur das Rootscope als Eigenschaft '$ root' hinzugefügt. Daher können wir nur über die Eigenschaft $ root im neuen isolierten Bereich auf die Eigenschaften von Rootscope zugreifen.

Adarsh ​​Sharma
quelle