AngularJS greift vom untergeordneten Controller auf den übergeordneten Bereich zu

382

Ich habe meine Controller mit eingerichtet data-ng-controller="xyzController as vm"

Ich habe ein Szenario mit übergeordneten / untergeordneten verschachtelten Controllern. Ich habe kein Problem damit, mithilfe von auf übergeordnete Eigenschaften im verschachtelten HTML zuzugreifen $parent.vm.property, kann jedoch nicht herausfinden, wie ich über meinen untergeordneten Controller auf die übergeordnete Eigenschaft zugreifen kann.

Ich habe versucht, $ scope zu injizieren und dann zu verwenden $scope.$parent.vm.property, aber das funktioniert nicht?

Kann mir jemand einen Rat geben?

zpydee
quelle

Antworten:

620

Wenn Ihr HTML-Code wie folgt ist, können Sie Folgendes tun:

<div ng-controller="ParentCtrl">
    <div ng-controller="ChildCtrl">
    </div>
</div>

Anschließend können Sie wie folgt auf den übergeordneten Bereich zugreifen

function ParentCtrl($scope) {
    $scope.cities = ["NY", "Amsterdam", "Barcelona"];
}

function ChildCtrl($scope) {
    $scope.parentcities = $scope.$parent.cities;
}

Wenn Sie aus Ihrer Sicht auf einen übergeordneten Controller zugreifen möchten, müssen Sie Folgendes tun:

<div ng-controller="xyzController as vm">
   {{$parent.property}}
</div>

Siehe jsFiddle: http://jsfiddle.net/2r728/

Aktualisieren

Da Sie citiesim übergeordneten Controller definiert haben, erbt Ihr untergeordneter Controller alle Bereichsvariablen. Theoretisch müssen Sie also nicht anrufen $parent. Das obige Beispiel kann auch wie folgt geschrieben werden:

function ParentCtrl($scope) {
    $scope.cities = ["NY","Amsterdam","Barcelona"];
}

function ChildCtrl($scope) {
    $scope.parentCities = $scope.cities;
}

Die AngularJS-Dokumente verwenden diesen Ansatz. Hier können Sie mehr über die lesen $scope.

Ein weiteres Update

Ich denke, dies ist eine bessere Antwort auf das Originalplakat.

HTML

<div ng-app ng-controller="ParentCtrl as pc">
    <div ng-controller="ChildCtrl as cc">
        <pre>{{cc.parentCities | json}}</pre>
        <pre>{{pc.cities | json}}</pre>
    </div>
</div>

JS

function ParentCtrl() {
    var vm = this;
    vm.cities = ["NY", "Amsterdam", "Barcelona"];
}

function ChildCtrl() {
    var vm = this;
    ParentCtrl.apply(vm, arguments); // Inherit parent control

    vm.parentCities = vm.cities;
}

Wenn Sie die controller asMethode verwenden, können Sie auch wie folgt auf den übergeordneten Bereich zugreifen

function ChildCtrl($scope) {
    var vm = this;
    vm.parentCities = $scope.pc.cities; // note pc is a reference to the "ParentCtrl as pc"
}

Wie Sie sehen, gibt es viele verschiedene Möglichkeiten für den Zugriff $scopes.

Geige aktualisiert

function ParentCtrl() {
    var vm = this;
    vm.cities = ["NY", "Amsterdam", "Barcelona"];
}
    
function ChildCtrl($scope) {
    var vm = this;
    ParentCtrl.apply(vm, arguments);
    
    vm.parentCitiesByScope = $scope.pc.cities;
    vm.parentCities = vm.cities;
}
    
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.min.js"></script>
<div ng-app ng-controller="ParentCtrl as pc">
  <div ng-controller="ChildCtrl as cc">
    <pre>{{cc.parentCities | json}}</pre>
    <pre>{{cc.parentCitiesByScope | json }}</pre>
    <pre>{{pc.cities | json}}</pre>
  </div>
</div>

Dieterg
quelle
6
Ich denke, die beiden Probleme bei Ihrem letzten Update sind: 1. Das Erben des übergeordneten Bereichs kann zu potenziellen Namespace-Konflikten führen. 2. Erfordert das Wissen, dass der Alias ​​des übergeordneten Controllers "pc" ist. Dies erschwert die Wiederverwendung.
Tchen
2
Sie haben Controller als Funktion CtrlName (...) {} definiert, aber wie können wir dies mithilfe der Angular-Nomenklatur erreichen? wie: angle.module (MdlName) .controller (CtrlName, function (...) {});
Pedro Justo
1
Was meinst du? Ein Controller ist nur eine Funktion? dhangular.module('app').controller('ParentCtrl', ParentCtrl);
Dieterg
1
Entschuldigung, du hast recht! Verwenden Sie in der Methode 'controller as' '$ scope.pc.cities;' Der Zugriff auf die Städte der Eltern scheint mir ein "Schritt zurück" zu sein, denn wenn wir in childCtrl nicht die Eigenschaft "Städte" haben, wird automatisch auf die Städte der Eltern zugegriffen. Es gibt keinen anderen Weg, um dieses Problem zu lösen?
Pedro Justo
46

Ich habe gerade nachgesehen

$scope.$parent.someProperty

funktioniert bei mir.

und es wird sein

{{$parent.someProperty}}

für die Aussicht.

Stepan Suworow
quelle
hmmm, arbeitet nicht für mich. Ich frage mich, ob es mit dem Controller als VM-Syntax zu tun hat.
Zpydee
Wenn Sie den übergeordneten Controller benannt haben, würden Sie $ parent in die Vorlage einfügen und {{vm.someProperty}}
solbs
8

Wenn Sie asSyntax verwenden, ParentController as parentCtrlum einen Controller zu definieren, und dann auf die übergeordnete Bereichsvariable im untergeordneten Controller zugreifen, verwenden Sie Folgendes:

var id = $scope.parentCtrl.id;

Wobei der parentCtrlName des übergeordneten Controllers die asSyntax verwendet und ideine Variable ist, die in demselben Controller definiert ist.

Rubi saini
quelle
2

Manchmal müssen Sie möglicherweise die übergeordneten Eigenschaften direkt im untergeordneten Bereich aktualisieren. zB müssen nach Änderungen durch einen untergeordneten Controller ein Datum und eine Uhrzeit der übergeordneten Steuerung gespeichert werden. zB Code in JSFiddle

HTML

<div ng-app>
<div ng-controller="Parent">
    event.date = {{event.date}} <br/>
    event.time = {{event.time}} <br/>
    <div ng-controller="Child">
        event.date = {{event.date}}<br/>
        event.time = {{event.time}}<br/>
        <br>
        event.date: <input ng-model='event.date'><br>
        event.time: <input ng-model='event.time'><br>
    </div>
</div>

JS

    function Parent($scope) {
       $scope.event = {
        date: '2014/01/1',
        time: '10:01 AM'
       }
    }

    function Child($scope) {

    }
Gayan Pathirage
quelle
1

Sie können auch die Bereichsvererbung umgehen und Dinge im "globalen" Bereich speichern.

Wenn Ihre Anwendung einen Hauptcontroller enthält, der alle anderen Controller umschließt, können Sie einen "Hook" für den globalen Bereich installieren:

function RootCtrl($scope) {
    $scope.root = $scope;
}

Dann können Sie in jedem untergeordneten Controller mit auf den "globalen" Bereich zugreifen $scope.root. Alles, was Sie hier einstellen, ist global sichtbar.

Beispiel:

function RootCtrl($scope) {
  $scope.root = $scope;
}

function ChildCtrl($scope) {
  $scope.setValue = function() {
    $scope.root.someGlobalVar = 'someVal';
  }
}

function OtherChildCtrl($scope) {
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app ng-controller="RootCtrl">
  
  <p ng-controller="ChildCtrl">
    <button ng-click="setValue()">Set someGlobalVar</button>
  </p>
  
  <p ng-controller="OtherChildCtrl">
    someGlobalVar value: {{someGlobalVar}}
  </p>

</div>

Rustyx
quelle
Das skaliert nicht wirklich. Es ist wie das Definieren globaler Variablen, die in vielen Dateien / Kontexten eindeutig sein müssen.
ZachB
Ich sehe kein Skalierungsproblem, aber das Aufrufen der Bereichsvariablen etwas anderes als "root" könnte in anderen Kontexten besser sein
Nico Westerdale
Es ist auch ein bisschen lästig, einen Zustand zu haben, der länger als die Lebensdauer des Komponenten-Unterbaums, der ihn benötigt, herumhängt.
Roboprog
0

Ich glaube, ich hatte kürzlich ein ähnliches Dilemma

function parentCtrl() {
   var pc = this; // pc stands for parent control
   pc.foobar = 'SomeVal';
}

function childCtrl($scope) {

   // now how do I get the parent control 'foobar' variable?
   // I used $scope.$parent

   var parentFoobarVariableValue = $scope.$parent.pc.foobar;

   // that did it
}

Mein Setup war etwas anders, aber das gleiche sollte wahrscheinlich immer noch funktionieren

Benjamin Thvedt
quelle
0

Von einer untergeordneten Komponente aus können Sie mit 'require' auf die Eigenschaften und Methoden der übergeordneten Komponente zugreifen. Hier ist ein Beispiel:

Elternteil:

.component('myParent', mymodule.MyParentComponent)
...
controllerAs: 'vm',
...
var vm = this;
vm.parentProperty = 'hello from parent';

Kind:

require: {
    myParentCtrl: '^myParent'
},
controllerAs: 'vm',
...
var vm = this;
vm.myParentCtrl.parentProperty = 'hello from child';
Donato Szilagyi
quelle
0

Super einfach und funktioniert, aber nicht sicher warum ....

angular.module('testing')
  .directive('details', function () {
        return {
              templateUrl: 'components/details.template.html',
              restrict: 'E',                 
              controller: function ($scope) {
                    $scope.details=$scope.details;  <=== can see the parent details doing this                     
              }
        };
  });
John Peters
quelle
-1

Vielleicht ist das lahm, aber Sie können beide auch einfach auf ein externes Objekt richten:

var cities = [];

function ParentCtrl() {
    var vm = this;
    vm.cities = cities;
    vm.cities[0] = 'Oakland';
}

function ChildCtrl($scope) {
    var vm = this;
    vm.cities = cities;
}

Der Vorteil hierbei ist, dass Änderungen in ChildCtrl jetzt auf die Daten im übergeordneten Element zurückgreifen.

Peter Hollingsworth
quelle
Die Einführung globaler Variablen ist gefährlich.
Dementic