AngularJS - Zugriff auf den untergeordneten Bereich


110

Wenn ich folgende Controller habe:

function parent($scope, service) {
    $scope.a = 'foo';

    $scope.save = function() {
        service.save({
            a:  $scope.a,
            b:  $scope.b
        });
    }
}

function child($scope) {
    $scope.b = 'bar';
}

Was ist der richtige Weg zu lassen , parentlesen bvon aus child? Wenn es notwendig ist , zu definieren , bin parent, würde nicht das macht es semantisch falsch davon aus, dass beine Eigenschaft ist , die etwas im Zusammenhang mit beschrieben childund nicht parent?

Update: Wenn mehr als ein Kind darüber bnachdenken würde, würde dies zu einem Konflikt führen, für parentden bes abgerufen werden könnte. Meine Frage bleibt, was ist der richtige Weg , um den Zugang bvon parent?


1
Lesen Sie auch Folgendes : stackoverflow.com/questions/14049480/… Eine sehr gute und detaillierte Übersicht über Bereiche und Vererbung in angleJS.
Martijn

Antworten:


162

Bereiche in AngularJS verwenden die prototypische Vererbung. Wenn Sie eine Eigenschaft in einem untergeordneten Bereich suchen, sucht der Interpreter die Prototypkette ausgehend vom untergeordneten Element und fährt mit den Eltern fort, bis die Eigenschaft gefunden wird, und nicht umgekehrt.

Überprüfen Sie die Kommentare von Vojta zum Problem https://groups.google.com/d/msg/angular/LDNz_TQQiNE/ygYrSvdI0A0J

Kurz gesagt: Sie können nicht über einen übergeordneten Bereich auf untergeordnete Bereiche zugreifen.

Ihre Lösungen:

  1. Definieren Sie Eigenschaften in Eltern und greifen Sie von Kindern darauf zu (lesen Sie den obigen Link).
  2. Verwenden Sie einen Dienst, um den Status freizugeben
  3. Daten durch Ereignisse leiten. $emitSendet Ereignisse nach oben an die Eltern, bis der Stammbereich erreicht ist, und sendet Ereignisse nach $broadcastunten. Dies kann Ihnen helfen, die Dinge semantisch korrekt zu halten.

8
Der Unterschied zwischen $ emit und $ Broadcast besteht darin, dass $ emit stornierbar ist und $ Broadcast nicht.
Azri Jamil

Ein Ort, an dem Sie wahrscheinlich den untergeordneten Bereich erhalten möchten, sind Anweisungen zum Testen von Einheiten. Wenn Sie eine transcluded-Direktive haben, ist der Bereich ein untergeordnetes Element des Bereichs, der zum Kompilieren des Elements verwendet wird. Der Zugriff auf den Geltungsbereich der kompilierten Direktive zum Testen ist eine Herausforderung.
PMC

Vielen Dank. Eine andere Option könnte localStoragemit einer Abhängigkeit wie sein ngStorage.
Akash

81

Während die Antwort von jm-s der beste Weg ist, um diesen Fall zu behandeln, ist es zum späteren Nachschlagen möglich, mit den Mitgliedern $$ childHead, $$ childTail, $$ nextSibling und $$ prevSibling auf untergeordnete Bereiche zuzugreifen. Diese sind nicht dokumentiert, sodass sie sich möglicherweise ohne vorherige Ankündigung ändern. Sie sind jedoch vorhanden, wenn Sie wirklich Bereiche durchlaufen müssen.

// get $$childHead first and then iterate that scope's $$nextSiblings
for(var cs = scope.$$childHead; cs; cs = cs.$$nextSibling) {
    // cs is child scope
}

Geige


49

Sie können dies versuchen:

$scope.child = {} //declare it in parent controller (scope)

Fügen Sie dann im untergeordneten Controller (Bereich) Folgendes hinzu:

var parentScope = $scope.$parent;
parentScope.child = $scope;

Jetzt hat der Elternteil Zugriff auf den Bereich des Kindes.


1
Sehr sauber und unkompliziert. Um dies hinzuzufügen, stellen Sie einfach fest, dass es keine Bindung gibt. Wenn Sie es also wie oben deklarieren, hält parentScope.child in diesem Moment den Bereich des Kindes. Um dies zu lösen, können Sie $ scope hinzufügen. $ Watch (function () {parentScope.child = $ scope}); so dass nach jedem Digest der neue Bereich zum übergeordneten Element verschoben wird. Wenn Sie auf der übergeordneten Seite einen der untergeordneten Bereiche für Visualisierungen im HTML-Code verwenden, müssen Sie eine Überwachung für die untergeordnete Variable hinzufügen und ihn anweisen, den Bereich wie folgt zu aktualisieren: $ scope. $ Watch ('child', function ( ) {$ scope. $ evalAsync ();}); . Hoffe das spart jemandem etwas Zeit!
IfTrue

2
@IfTrue Ich glaube, eine $ watch () ist nicht erforderlich. Dies sind Objekte, die als Referenz dienen.
Swanidhi

2
@Swanidhi = Ich weiß, was du meinst und ich dachte es auch, aber es hat nicht funktioniert, als ich zum Zeitpunkt des Schreibens des Kommentars experimentiert habe. Für das, was es wert ist, habe ich von diesem auf Senden / Senden umgestellt.
IfTrue

1
Wie mache ich das in Type Script?
ATHER

Beste Antwort für mich !! Bestes Beispiel für Objekte, die in Javascript als Referenz behandelt werden
Vikas Gautam

4

Eine mögliche Problemumgehung besteht darin, den untergeordneten Controller mithilfe einer Init-Funktion in den übergeordneten Controller einzufügen.

Mögliche Implementierung:

<div ng-controller="ParentController as parentCtrl">
   ...

    <div ng-controller="ChildController as childCtrl" 
         ng-init="ChildCtrl.init()">
       ...
    </div>
</div>

Wo in ChildControllerdir hast:

app.controller('ChildController',
    ['$scope', '$rootScope', function ($scope, $rootScope) {
    this.init = function() {
         $scope.parentCtrl.childCtrl = $scope.childCtrl;
         $scope.childCtrl.test = 'aaaa';
    };

}])

So, jetzt in der können ParentControllerSie verwenden:

app.controller('ParentController',
    ['$scope', '$rootScope', 'service', function ($scope, $rootScope, service) {

    this.save = function() {
        service.save({
            a:  $scope.parentCtrl.ChildCtrl.test
        });
     };

}])

Wichtig:
Um richtig zu funktionieren, müssen Sie die Direktive verwenden ng-controllerund jeden Controller umbenennen, aswie ich es im HTML getan habe, z.

Tipps:
Verwenden Sie während des Vorgangs den Chrome Plugin ng-Inspector . Es wird Ihnen helfen, den Baum zu verstehen.


3

Verwenden von $ emit und $ Broadcast (wie von walv in den obigen Kommentaren erwähnt)

Ein Ereignis nach oben auslösen (vom Kind zum Elternteil)

$scope.$emit('myTestEvent', 'Data to send');

Ein Ereignis nach unten auslösen (vom Elternteil zum Kind)

$scope.$broadcast('myTestEvent', {
  someProp: 'Sending you some data'
});

und schließlich zuzuhören

$scope.$on('myTestEvent', function (event, data) {
  console.log(data);
});

Für weitere Informationen: - https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

Genießen :)


1

Ja, wir können den Variablen im übergeordneten Controller Variablen vom untergeordneten Controller zuweisen. Dies ist ein möglicher Weg:

Übersicht: Das Hauptziel des folgenden Codes besteht darin, die $ scope.variable des untergeordneten Controllers der $ scope.assign des übergeordneten Controllers zuzuweisen

Erläuterung: Es gibt zwei Controller. Beachten Sie im HTML, dass der übergeordnete Controller den untergeordneten Controller einschließt. Das heißt, der übergeordnete Controller wird vor dem untergeordneten Controller ausgeführt. Also wird zuerst setValue () definiert und dann geht das Steuerelement zum untergeordneten Controller. $ scope.variable wird als "Kind" zugewiesen. Dann wird dieser untergeordnete Bereich als Argument an die Funktion des übergeordneten Controllers übergeben, wobei $ scope.assign den Wert "child" erhält.

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script type="text/javascript">
    var app = angular.module('myApp',[]);

    app.controller('child',function($scope){
        $scope.variable = "child";
        $scope.$parent.setValue($scope);
    });

    app.controller('parent',function($scope){
        $scope.setValue = function(childscope) {
            $scope.assign = childscope.variable;
        }
    });

</script>
<body ng-app="myApp">
 <div ng-controller="parent">
    <p>this is parent: {{assign}}</p>
    <div ng-controller="child">
        <p>this is {{variable}}</p>
    </div>
 </div>
</body>
</html>
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.