AngularJS accède à la portée parent à partir du contrôleur enfant

382

J'ai configuré mes contrôleurs en utilisant data-ng-controller="xyzController as vm"

J'ai un scénario avec des contrôleurs imbriqués parent / enfant. Je n'ai aucun problème pour accéder aux propriétés parent dans le html imbriqué en utilisant $parent.vm.property, mais je ne peux pas comprendre comment accéder à la propriété parent à partir de mon contrôleur enfant.

J'ai essayé d'injecter $ scope puis de l'utiliser $scope.$parent.vm.property, mais cela ne fonctionne pas?

Quelqu'un peut-il donner des conseils?

zpydee
la source

Réponses:

620

Si votre code HTML est comme ci-dessous, vous pouvez faire quelque chose comme ceci:

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

Ensuite, vous pouvez accéder à la portée parent comme suit

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

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

Si vous souhaitez accéder à un contrôleur parent à partir de votre vue, vous devez faire quelque chose comme ceci:

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

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

Mise à jour

En fait, puisque vous avez défini citiesdans le contrôleur parent, votre contrôleur enfant héritera de toutes les variables de portée. Donc, théoriquement, vous n'avez pas à appeler $parent. L'exemple ci-dessus peut également s'écrire comme suit:

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

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

Les documents AngularJS utilisent cette approche, ici vous pouvez en savoir plus sur le $scope.

Une autre mise à jour

Je pense que c'est une meilleure réponse à l'affiche originale.

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;
}

Si vous utilisez la controller asméthode, vous pouvez également accéder à la portée parent comme suit

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

Comme vous pouvez le voir, il existe de nombreuses façons d'accéder $scopes.

Violon mis à jour

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
la source
6
Je pense que les deux problèmes avec votre dernière mise à jour sont 1. L'héritage de la portée parent peut avoir des conflits potentiels d'espace de noms, et 2. Nécessite la connaissance que l'alias du contrôleur parent est «pc». Cela rend la réutilisation plus difficile.
Tchen
2
Vous avez défini les contrôleurs comme la fonction CtrlName (...) {} mais comment pouvons-nous y parvenir en utilisant la nomenclature angulaire? comme: angular.module (MdlName) .controller (CtrlName, function (...) {});
Pedro Justo
1
Que voulez-vous dire? Un contrôleur n'est qu'une fonction? ieangular.module('app').controller('ParentCtrl', ParentCtrl);
Dieterg
1
désolé, vous avez raison! Dans la méthode 'controller as', en utilisant '$ scope.pc.cities;' accéder aux villes des parents me semble un «pas en arrière» car si dans childCtrl nous n'avons pas la propriété «villes», il accèdera automatiquement aux villes des parents. Il n'y a pas d'autre moyen de résoudre ce problème?
Pedro Justo
46

Je viens de vérifier

$scope.$parent.someProperty

travaille pour moi.

et ce sera

{{$parent.someProperty}}

pour la vue.

Stepan Suvorov
la source
hmmm, ne fonctionne pas pour moi. Je me demande si cela a à voir avec le contrôleur comme syntaxe vm.
zpydee
Si vous avez nommé le contrôleur parent, vous déposerez $ parent dans le modèle et aurez {{vm.someProperty}}
solbs le
8

Lorsque vous utilisez la assyntaxe, comme ParentController as parentCtrlpour définir un contrôleur, puis pour accéder à la variable de portée parent dans le contrôleur enfant, utilisez ce qui suit:

var id = $scope.parentCtrl.id;

parentCtrlest le nom du contrôleur parent utilisant la assyntaxe et idest une variable définie dans le même contrôleur.

Rubi saini
la source
2

Parfois, vous devrez peut-être mettre à jour les propriétés parent directement dans la portée enfant. par exemple, besoin de sauvegarder une date et une heure du contrôle parent après les modifications par un contrôleur enfant. par exemple Code dans 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
la source
1

Vous pouvez également contourner l'héritage de portée et stocker des éléments dans la portée "globale".

Si vous avez un contrôleur principal dans votre application qui encapsule tous les autres contrôleurs, vous pouvez installer un "raccordement" à la portée globale:

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

Ensuite, dans n'importe quel contrôleur enfant, vous pouvez accéder à la portée "globale" avec $scope.root. Tout ce que vous définissez ici sera globalement visible.

Exemple:

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
la source
Ce n'est pas vraiment à l'échelle. C'est comme définir des variables globales qui doivent être uniques dans de nombreux fichiers / contextes.
ZachB
Je ne vois pas de problème de mise à l'échelle, mais appeler la variable d'étendue autre que «root» pourrait être mieux dans d'autres contextes
Nico Westerdale
C'est aussi un peu gênant d'avoir un état qui dure plus longtemps que la durée de vie de la sous-arborescence des composants qui en a besoin.
Roboprog
0

Je crois avoir eu un dilemme similaire récemment

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
}

Ma configuration était un peu différente, mais la même chose devrait probablement encore fonctionner

Benjamin Thvedt
la source
0

À partir d'un composant enfant, vous pouvez accéder aux propriétés et méthodes du composant parent avec «require». Voici un exemple:

Parent:

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

Enfant:

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

Super facile et fonctionne, mais je ne sais pas pourquoi ....

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
la source
-1

C'est peut-être boiteux, mais vous pouvez également les pointer vers un objet externe:

var cities = [];

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

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

L'avantage ici est que les modifications dans ChildCtrl se propagent désormais aux données dans le parent.

Peter Hollingsworth
la source
l'introduction de variables globales est dangereuse.
Dementic